sorry for the n00bness of this but the searching i’ve done hasn’t turned up anything
that addresses directly my, i think, very simple problem.
my canon camera decided to help me by putting all of its still images into folders
of a maximum of 100 jpg files. i thought i’d just be able to process all of the files
together but i now find i have to go through and copy the contents of a lot of sub-
folders into a temp folder before i can work with them.
i have this, which locates the folder containing the subfolders with the jpgs:
-- where are the original frames stored?
set sourceFolder to "Canon:DCIM:"
set tempFolder to "RAID:Canon_TEMP:"
-- count the folders in the DCIM folder
tell application "Finder"
set folderCount to count of (folders in folder sourceFolder)
end tell
i figured i’d need to count the subfolders to define the parameter of a repeat loop
but can’t figure out how to get through it. the counting seems to work fine.
how do i make a repeat loop that copies all of the jpg’s from each subfolder to my
temp folder? fwiw, the DCIM folder only contains subfolders containing my jpg’s, no
other folders or files. the subfolders contain only jpg files, no others. i need to copy
everything from each subfolder in the DCIM folder to my temp folder.
It’s usually best to get a list of the folder references and then work with the list:
set sourceFolder to "Canon:DCIM:"
set tempFolder to "RAID:Canon_TEMP:"
tell application "Finder"
set sourceSubfolders to folders in folder sourceFolder
repeat with i from 1 to (count sourceSubfolders)
set thisSubfolder to item i of sourceSubfolders
duplicate thisSubfolder's files to folder tempFolder
end repeat
end tell
Or:
set sourceFolder to "Canon:DCIM:"
set tempFolder to "RAID:Canon_TEMP:"
tell application "Finder"
set sourceSubfolders to folders in folder sourceFolder
repeat with thisSubfolder in sourceSubfolders
duplicate thisSubfolder's files to folder tempFolder
end repeat
end tell
But the Finder can in fact be told to do this without a repeat loop:
set sourceFolder to "Canon:DCIM:"
set tempFolder to "RAID:Canon_TEMP:"
tell application "Finder"
duplicate files of entire contents of folder sourceFolder to folder tempFolder
end tell
These all assume that none of the files have the same name.
thanks to you both for the replies. i spent most of a day googling and reading but hadn’t found anything
specific to this issue. never did see anything on flattening folder hierarchy. will look at that.
i’ll probably pursue one of the repeat loops rather than the direct finder approach. seems like changes
that might develop in the folder structures (like non jpg files being found in the subfolders, or other
types of subfolders being added) might be more easily addressed (at least by me) with the repeat
loop structure. will try that later today when i get back to that machine.
one thing that always throws me off is in the line from nigel’s second example:
repeat with thisSubfolder in sourceSubfolders
it seems to add a new variable ‘thisSubfolder’ without the ‘set’ command.
AppleScript can filter the items found by any of their attributes:
tell application "Finder"
set allMyJpegs to files of entire contents of folder sourceFolder whose name extension is "jpg"
end tell
Generally, a filter looks like this: … whose is . “Files of” is also a filter: it gets files from “entire contents”, which also contains all subfolders.
What other types?? A folder is a folder is folder…
Using “entire contents” is completely safe, and faster than using loops, as Finder is doing all the, um, finding, not your script.
Actually, as with many applications, the more decisions the Finder has to make, the slower it becomes. It also takes a while to return long lists of Finder references. So it’s often better to let the script do the thinking, even though it means more code.
With a folder on my machine containing 569 images and no subfolders, the following script takes 5.073 seconds to execute (as measured by Tetsuro Kurita’s LapTime OSAX):
tell application "Finder"
set f to target of front Finder window
files of f
end tell
"Done" -- This just saves the time it would take AppleScript Editor to display all the Finder references in the result.
Changing the third line to ‘files of the entire contents of f’ increases the time to 32.926 seconds, even though they’re exactly the same files. And appending a ‘whose’ filter to get only those files with “jpg” name extensions increases the time to 58.881 seconds.
But this only takes 0.295 seconds:
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to linefeed
tell application "Finder"
set f to target of front Finder window
set paths to paragraphs of ((files of entire contents of f) as text)
end tell
set AppleScript's text item delimiters to astid
repeat with thisPath in paths
if (thisPath does not end with ".jpg") then set thisPath's contents to missing value
end repeat
paths's text -- Gives a list containing only the surviving texts, not the missing values.
"Done"
The result is a list of HFS paths rather than of Finder references, but the Finder understands those and the list can be used as the direct object of a ‘duplicate’ command:
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to linefeed
tell application "Finder"
set f to target of front Finder window
set paths to paragraphs of ((files of entire contents of f) as text)
end tell
set AppleScript's text item delimiters to astid
repeat with thisPath in paths
if (thisPath does not end with ".jpg") then set thisPath's contents to missing value
end repeat
set paths to paths's text
tell application "Finder" to duplicate paths to folder "untitled folder" of desktop
"Done"
519 of my 569 files have “jpg” or “JPG” name extensions and the entire process, including the duplication, takes just 13.69 seconds.
Many will be keen to point out that using a shell script would be much faster still, but I just wanted to point out here that taking the trouble to write your own vanilla code can have advantages over relying on applications’ filter “shortcuts”.
You’re true when the apple events are handled correctly by the Application. But in this case apparently it isn’t, but I understand completely your assumption. You would say that a Filter in a compiled language (which will be simple code jumping in machine code) will be at least hundred times faster than a scripting language.
Hi, Nigel. I’m a big proponent of reducing events to their lowest possible number, and I’ve personally never seen a slower result returned from the “entire contents” expression, unless Finder was accessing multiple subfolders. I didn’t use the OSAX to time it, but I’ve experienced unequal results to yours on a test with a similar quantity of files. Both “files of f” and “files of entire contents of f” returned a result of under one second on my machine, which is a lowly G4 Mac Mini running OS 10.4.11. There may be an unforeseen variable that is causing your time to balloon to 32 seconds, perhaps a difference in the OS or other active processes.
Hmm. I restarted my computer yesterday. Although the ‘files of f’ script takes about the same amount of time, the ‘file of entire contents of f’ version now only takes about 12 or 13 seconds.
I was testing with an open window, of course. If I hardwire the folder reference into the script and close the window, there’s an even more dramatic speed-up. Two and a half seconds with ‘files’ and three seconds with ‘files of entire contents’.
But it’s still a lot faster to get the result as text.
not a reference to applescript here. i was referring to folders on the canon which
canon might use for other than jpg purposes. the folders i’ve encountered thus far
have all been for images. i have no idea if there could be a circumstance now or
in the future in which folders might appear in the DCIM folder which contain files
other than jpgs.
thanks for all of the input on this. very helpful. i’ve got my script running now. the
benchmarks posted here were interesting.