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
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
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.
I had a somewhat similar need to that addressed above, but this time I needed to sort an array of file URLs by the path of the containing folder and then by file name. This turned out to be surprisingly difficult, although the solution (path.stringByDeletingLastPathComponent) was simple. The likelihood that anyone would have need of this are slim, but I thought I’d post the solution just in case.
use framework "Foundation"
use scripting additions
set theFolder to current application's NSURL's fileURLWithPath:"/Users/Robert/Test/"
set fileManager to current application's NSFileManager's defaultManager()
set folderContents to (fileManager's enumeratorAtURL:theFolder includingPropertiesForKeys:{} options:6 errorHandler:(missing value))'s allObjects()
set thePredicates to current application's NSPredicate's predicateWithFormat:"self.hasDirectoryPath == false"
set theFiles to (folderContents's filteredArrayUsingPredicate:thePredicates)
set pathDescriptor to current application's NSSortDescriptor's sortDescriptorWithKey:"path.stringByDeletingLastPathComponent" ascending:true selector:"localizedStandardCompare:"
set nameDescriptor to current application's NSSortDescriptor's sortDescriptorWithKey:"lastPathComponent" ascending:true selector:"localizedStandardCompare:"
set sortedURLs to theFiles's sortedArrayUsingDescriptors:{pathDescriptor, nameDescriptor}