Create Multiple Folders with Files from a Single Folder with Files

Not sure how to wrap my head around this one, solution needs to work in Tiger. It’s for me personally so no user UI is required…variables can be used for all limits and checks without UI prompts.


I have a folder with a huge number of files (over 17,000) that I want to break-out into multiple smaller folders with a simple serial number scheme:

FolderName 001
FolderName 002
FolderName 003

The idea is I want a routine that will:

1…Choose a random batch of files from the master folder, up to a given total size limit (i.e. total size of files chosen cannot exceed some limit)

2…Create a serial-numbered folder

3…Copy (not move) the chosen files into the folder

4…Keep going until the entire master folder is batched into serialized folders without duplicates


Basically I have a Palm Pilot I’d like to keep a rotating bunch of photos on via SD cards (hence the fixed size per folder). I have an AppleScript that I used to convert my photos to Palm sizes and those are all saved into a master folder. I add and subtract from this folder now and again, and would simply re-do the batches from time to time by re-running the above script. I know it would take a while to run, that’s okay. Or I could do sub-batches by changing the “master” folder I use it on.

Been trying to figure out how to go about it, but I’ve apprently got Coder’s Block, due to lack of time no doubt. Hoping y’all could help, with my gratitude of course!

This will be slow. It would be greatly sped up using a shell script.

tell application "Finder"
	set first_folder to (choose folder) as alias
	set everyfile to every file in folder first_folder
	set n to count of items in everyfile
	if n > 3 then
		set f1 to name of first_folder & " 001" as text
		set f2 to name of first_folder & " 002" as text
		set f3 to name of first_folder & " 003" as text
		set stop1 to n / 3 as integer
		set stop2 to n * 2 / 3 as integer
		set newf1 to (make new folder at folder first_folder with properties {name:f1}) as alias
		set newf2 to (make new folder at folder first_folder with properties {name:f2}) as alias
		set newf3 to (make new folder at folder first_folder with properties {name:f3}) as alias
		repeat with i from 1 to stop1
			copy item i of everyfile to folder newf1
		end repeat
		repeat with j from i to stop2
			copy item j of everyfile to folder newf2
		end repeat
		repeat with k from j to n
			copy item k of everyfile to folder newf3
		end repeat
	end if
end tell

Three questions:

–Where is the Random element handled? (i.e. pick random files from the master folder, but never pick the same ones twice while propogating the created new serialized folders)

–What about more than 3 folders (sorry, I should have mentioned the script needs to know when to create folder 4, 5, 6, etc.)

–What about a size limit (i.e. how is it figuring out if the files it’s picked don’t exceed some total size)?

Oh, and I’m not being facietious, just to be clear. I can’t tell if these elements are there and I don’t see them (wouldn’t be the first time), or if they aren’t there because I wasn’t clear in my needs, or whatnot.

I know this is a complicated/wierd/messy one, else I wouldn’t have asked. My own personal stumbling blocks are I’m not sure how to handle the random element and size detection, and no duplicates. Too many conditions at once!

Oh, and I have no aversion to shell, as long as it’s AppleScript directing shell, and you’re willing to explain it to me. Whenever I ask for a “solution” like this, I always dissect it to figure out how it works so I can learn and use that knowledge so I don’t have to pester y’all the next time similar stuff comes up. :wink:

Thanks again!

Sorry, I guess I should have paid more attention to what you were asking for. I’ll try to add some of those things…

Ok, this creates enough folders to make the average subfolder hold less than 100 MB of data, but it doesn’t put limits on any individual folder. I’ll try to work on that later if I get time. :wink:

tell application "Finder"
	set MaxSize to 100
	set subfolders to {}
	set folder_stops to {}
	set folder_stops to 0
	set first_folder to (choose folder) as alias
	set everyfile to every file in folder first_folder
	set n to count of items in everyfile
	set sz to size of folder first_folder
	set sz to sz / 1048576 as real
	set newcount to 1
	set newsize to sz
	repeat while newsize > MaxSize
		set newsize to sz / newcount
		set newcount to newcount + 1
	end repeat
	set stoppoints to n / newcount
	repeat with f from 1 to newcount
		set folder_stops to folder_stops & (stoppoints * f as integer)
		set nn to " " & (f as text) as text
		set new_folder to name of first_folder & nn as text
		set new_folder_alias to (make new folder at folder first_folder with properties {name:new_folder}) as alias
		set subfolders to subfolders & new_folder_alias
	end repeat
	repeat with f from 1 to newcount
		set dest to item f of subfolders
		set start to (item f of folder_stops) + 1
		set fin to item (f + 1) of folder_stops
		repeat with c from start to fin
			copy item c of everyfile to folder dest
		end repeat
	end repeat
end tell

Here it is using a do shell script command. It should be faster.

tell application "Finder"
	set MaxSize to 100
	set subfolders to {}
	set folder_stops to {}
	set folder_stops to 0
	set first_folder to (choose folder) as alias
	set Firstfo to (POSIX path of first_folder) as text
	set everyfile to every file in folder first_folder
	set n to count of items in everyfile
	set sz to size of folder first_folder as real
	set sz to sz / 1048576
	set newcount to 1
	set newsize to sz
	repeat while newsize > MaxSize
		set newsize to sz / newcount
		set newcount to newcount + 1
	end repeat
	set stoppoints to n / newcount
	repeat with f from 1 to newcount
		set folder_stops to folder_stops & (stoppoints * f as integer)
		set nn to " " & (f as text) as text
		set new_folder to name of first_folder & nn as text
		set new_folder_alias to (make new folder at folder first_folder with properties {name:new_folder}) as alias
		set subfolders to subfolders & new_folder_alias
	end repeat
	repeat with f from 1 to newcount
		set dest to item f of subfolders
		set destf to POSIX path of dest
		set start to (item f of folder_stops) + 1
		set fin to item (f + 1) of folder_stops
		
		repeat with c from start to fin
			set filename to name of item c of everyfile
			set destfile to quoted form of (destf & filename)
			set comm to "cp " & quoted form of (Firstfo & filename) & " " & destfile
			ignoring application responses
				do shell script comm
			end ignoring
		end repeat
	end repeat
end tell

This plain vanilla AppleScript works for me in limited testing – it doesn’t create the folders or duplicate then remove (copy doesn’t work) the files, instead it creates a list of randomly chosen aliases and assigns them a folder number. Easy enough to use that for the moving, etc.:

set chosen to choose folder -- this is an alias
set tMax to 20000 -- folder limit in KBytes, has to be bigger than the largest file.
set idx to {}
set tSum to 0 -- total size of all files
set tLargest to 0
set whichFolder to 1
set toDup to {} -- a list of {alias, whichFolder} for the batch chosen
tell application "Finder"
	set tFiles to files in folder chosen as alias list
	set n to count tFiles
	-- get an index list of n in length
	repeat with k from 1 to n
		set end of idx to k
	end repeat
	-- get a list of the file sizes and the total size
	set Sizes to {}
	repeat with aFile in tFiles
		set tSize to (size of aFile) / 1000
		set end of Sizes to tSize
		set tSum to tSum + tSize
		if tSize > tLargest then set tLargest to tSize
	end repeat
	beep 3
	-- now make up the toDup lists
	set soFar to 0
	repeat until (count toDup) = n
		set Kval to some item of idx
		if Kval ≠ 0 then
			set Fsize to item Kval of Sizes
			if Fsize + soFar < tMax then
				set end of toDup to {item Kval of tFiles, whichFolder}
				set item Kval of idx to 0
				set soFar to soFar + Fsize
			else
				set whichFolder to whichFolder + 1
				set soFar to 0
			end if
		end if
	end repeat
end tell
toDup