It’s commonplace that I have to obtain files with a particular extension from one folder. I don’t recall where but I found the script included below. With one exception it does what I want, but I wondered if there might be any improvements:
on getFiles(sourceFolder, fileExtensions) -- sourceFolder is POSIX path and fileExtensions is list of file extensions
set fileManager to current application's NSFileManager's defaultManager()
set theFolder to current application's |NSURL|'s fileURLWithPath:sourceFolder
set folderContents to fileManager's contentsOfDirectoryAtURL:theFolder includingPropertiesForKeys:{} options:(current application's NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value)
set theFiles to current application's NSPredicate's predicateWithFormat_("pathExtension.lowercaseString IN %@", fileExtensions)
set theFiles to folderContents's filteredArrayUsingPredicate:theFiles
return theFiles as list
end getFiles
I need the returned list to be sorted by name in ascending order. I added a sort routine to the script but received an unrecognized-selector error, presumably because I cannot sort URL’s in this manner. I looked at the NSArrray and NSURL documentation but didn’t find a solution. How can I fix this or is there a better way.
on getFiles(sourceFolder, fileExtensions) -- sourceFolder is POSIX path and fileExtensions is list of file extensions
set fileManager to current application's NSFileManager's defaultManager()
set theFolder to current application's |NSURL|'s fileURLWithPath:sourceFolder
set folderContents to fileManager's contentsOfDirectoryAtURL:theFolder includingPropertiesForKeys:{} options:(current application's NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value)
set theFiles to current application's NSPredicate's predicateWithFormat_("pathExtension.lowercaseString IN %@", fileExtensions)
set theFiles to folderContents's filteredArrayUsingPredicate:theFiles
set sortedFiles to (theFiles's sortedArrayUsingSelector:"compare:") -- error "-[NSURL compare:]: unrecognized selector sent to instance 0x600001825e00" number -10000
return sortedFiles as list
end getFiles
Thanks for the help.
NSURL instances cannot be sorted with the compare selector – as stated by the error – because NSURL doesn’t represent a single value like a string.
A solution is to use a NSSortDescriptor which sorts the array by the file name (in terms of NSURL the last path component)
on getFiles(sourceFolder, fileExtensions) -- sourceFolder is POSIX path and fileExtensions is list of file extensions
set fileManager to current application's NSFileManager's defaultManager()
set theFolder to current application's |NSURL|'s fileURLWithPath:sourceFolder
set folderContents to fileManager's contentsOfDirectoryAtURL:theFolder includingPropertiesForKeys:{} options:(current application's NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value)
set theFiles to current application's NSPredicate's predicateWithFormat_("pathExtension.lowercaseString IN %@", fileExtensions)
set theFiles to folderContents's filteredArrayUsingPredicate:theFiles
set sortDescriptors to current application's NSArray's arrayWithObject:(current application's NSSortDescriptor's sortDescriptorWithKey:"lastPathComponent" ascending:true)
set sortedFiles to (theFiles's sortedArrayUsingDescriptors:sortDescriptors)
return sortedFiles as list
end getFiles
Thanks Stefan. That worked great.
FWIW, I ran some timing tests on the above script and the Finder equivalent. The test folder contained 20 PDF, 20 PNG, and 20 TXT files, and I set the scripts to get PDF files only. The first-run timing results were:
ASObjC - 0.028 seconds
Finder - 1.261 seconds
The ASObjC result is with the Foundation framework in memory, which would normally be the case if ASObjC is regularly used.
Here is example of sorted files in a folder as POSIX path
This example the repeat loop start at 4 because in the folder it had 3 hidden files.
Be a ware it also count folders, so I guess other approach would consider if that matters.
use framework "Foundation"
use scripting additions
set thePath to POSIX path of (path to desktop pictures folder)
set {theResult, theError} to (current application's NSFileManager's defaultManager())'s contentsOfDirectoryAtPath:thePath |error|:(reference)
set theSort to (theResult's sortedArrayUsingSelector:"compare:") as list
set theList to {}
repeat with i from 4 to count theSort
set theFilePath to thePath & item i of theSort
copy theFilePath to end of theList
end repeat
return theList
use framework "Foundation"
use scripting additions
return my sortedFileListAtPath:(POSIX path of (path to desktop pictures folder))
on sortedFileListAtPath:thePath
set {theResult, theError} to (current application's NSFileManager's defaultManager())'s contentsOfDirectoryAtPath:thePath |error|:(reference)
set theSort to (theResult's sortedArrayUsingSelector:"compare:") as list
set theList to {}
repeat with i from 4 to count theSort
set theFilePath to thePath & item i of theSort
copy theFilePath to end of theList
end repeat
return theList
end sortedFileListAtPath: