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.
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.
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