Page 1 of 1

Unflatten a folder

Posted: 21 Aug 2018 14:40
by pdupreez
After a lot of cleaning and de-duplication of my music folders, I now have a flat folder with all my duplicate files. I am not yet ready to delete these (50k+ files) just in case I need to fill an album which I have inadvertently deleted a file or two. Dealing with a folder with 50k+ files is however a pain in the neck, even with XYplorer and 32GB RAM.

I would like to unflatten the folder into an alphabetical structure, using the first element in the name as a start i.e.

1 song for you.mp3
My first song.mp3
The second Song.mp3
Free songs in a row.mp3

Should end up as

Base folder:\#\1 song for you.mp3
Base folder:\F\Free songs in a row.mp3
Base folder:\M\My first song.mp3
Base folder:\T\The second Song.mp3

Eventually I will end up with a structure that stretches
Base folder:\# (for anything not alphabetical)
Base folder:\A\files.xyz
Base folder:\B\files.xyz
Base folder:\C\files.xyz
.
.
.
Base folder:\Z\files.xyz

Re: Unflatten a folder

Posted: 21 Aug 2018 15:01
by jupe
Here is one way to do it, it might not be the fastest way though, but if you want to try it anyway just goto the main folder then run it, it has a built in preview although be prepared for it to take a little while before the preview window shows up with that amount of files.

Code: Select all

	$dest = "";
	setting "HideFoldersInList", 1;
	foreach($file, <get itemsnames |>) {
	  $prefix = recase(substr($file, 0, 1), "u");
	  if $prefix LikeI "[A-Z]" {
		 $dest .= $prefix . "\" . $file . "|";
	  } else {
		 $dest .= "#\" . $file . "|";
	  }
	}
	rename l, trim($dest, "|"), "p", <allitems |>;
This setting needs to be enabled for it to work though:
Configuration | General | Sort and Rename | Rename | Allow move on rename

Re: Unflatten a folder

Posted: 21 Aug 2018 17:07
by highend
Ok, here is how I'd do it (as always, heavy regex involved, be aware!)

Code: Select all

    setting "AutoRefresh", 0;
    $items = listfolder(, , 1+4, <crlf>);
    $prefixes = recase(formatlist(regexmatches($items, "^[a-z]"), "sd"), "u");
    foreach($prefix, $prefixes, , "e") { if (exists($prefix) != 2) { new($prefix, "dir"); } }

    $cItems = regexmatches($items, "^[a-z].+?(?=\r?\n|$)", <crlf>);
    $oItems = regexmatches($items, "^(?![a-z]).+?(?=\r?\n|$)", <crlf>);

    $oRItems = replace(regexreplace($oItems, "^(.+?)(?=\r?\n|$)", "#\$1"), <crlf>, "|");
    $cRItems = replace(regexreplace($cItems, "^([a-z])(.+?)(?=\r?\n|$)", "$1\$1$2"), <crlf>, "|");

    rename "l", $oRItems, , replace(regexreplace($oItems, "^(.+?)(?=\r?\n|$)", "<curpath>\$1"), <crlf>, "|");
    rename "l", $cRItems, , replace(regexreplace($cItems, "^(.+?)(?=\r?\n|$)", "<curpath>\$1"), <crlf>, "|");
It only needs at max 26 calls to create a new folder (a-z, depending on if you have files beginning with this char)
and then there are only two renames, one for all items that do not begin with a-z and one more for all others...

Unfortunately the regex engine does not support uppercasing matches, so creating the folders can't be avoided
if only two renames should be used...