The following script separately returns all folders and files contained within a user-selected folder:
use framework "Foundation"
use scripting additions
set sourceFolder to POSIX path of (choose folder)
set {theFolders, theFiles} to getFoldersAndFiles(sourceFolder)
on getFoldersAndFiles(sourceFolder)
set fileManager to current application's NSFileManager's defaultManager()
set sourceFolder to current application's |NSURL|'s fileURLWithPath:sourceFolder
set directoryKey to current application's NSURLIsDirectoryKey
set packageKey to current application's NSURLIsPackageKey
set theFiles to ((fileManager's enumeratorAtURL:sourceFolder includingPropertiesForKeys:{} options:6 errorHandler:(missing value))'s allObjects())'s mutableCopy() -- option 6 skips hidden files and package descendants
set theFolders to current application's NSMutableArray's new()
set booleanTrue to current application's NSNumber's numberWithBool:true
repeat with anItem in theFiles
set {theResult, aDirectory} to (anItem's getResourceValue:(reference) forKey:directoryKey |error|:(missing value))
if aDirectory is booleanTrue then
set {theResult, aPackage} to (anItem's getResourceValue:(reference) forKey:packageKey |error|:(missing value))
if not (aPackage is booleanTrue) then (theFolders's addObject:anItem)
end if
end repeat
theFiles's removeObjectsInArray:theFolders
return {theFolders as list, theFiles as list}
end getFoldersAndFiles
The following script is the same as the above except that it only returns folders and files whose names contain a user-specified search string:
use framework "Foundation"
use scripting additions
set sourceFolder to POSIX path of (choose folder)
set searchString to text returned of (display dialog "Enter a search string:" default answer "") -- case insensitive
set {theFolders, theFiles} to getFoldersAndFiles(sourceFolder, searchString)
on getFoldersAndFiles(sourceFolder, searchString)
set fileManager to current application's NSFileManager's defaultManager()
set sourceFolder to current application's |NSURL|'s fileURLWithPath:sourceFolder
set directoryKey to current application's NSURLIsDirectoryKey
set packageKey to current application's NSURLIsPackageKey
set theFiles to ((fileManager's enumeratorAtURL:sourceFolder includingPropertiesForKeys:{} options:6 errorHandler:(missing value))'s allObjects())'s mutableCopy() -- option 6 skips hidden files and package descendants
set thePredicate to current application's NSPredicate's predicateWithFormat_("lastPathComponent CONTAINS[c] %@", searchString)
theFiles's filterUsingPredicate:thePredicate
set theFolders to current application's NSMutableArray's new()
set booleanTrue to current application's NSNumber's numberWithBool:true
repeat with anItem in theFiles
set {theResult, aDirectory} to (anItem's getResourceValue:(reference) forKey:directoryKey |error|:(missing value))
if aDirectory is booleanTrue then
set {theResult, aPackage} to (anItem's getResourceValue:(reference) forKey:packageKey |error|:(missing value))
if not (aPackage is booleanTrue) then (theFolders's addObject:anItem)
end if
end repeat
(theFiles's removeObjectsInArray:theFolders)
return {theFolders as list, theFiles as list}
end getFoldersAndFiles
The above scripts return a list of file references. Change the last line of the handler to the following to return POSIX paths.
return {(theFolders's valueForKey:"path") as list, (theFiles's valueForKey:"path") as list}
Line 3 below exists in both of the scripts. Insert new lines 1 and 2 above existing line 3 to sort the returned results by path. Replace āpathā with ālastPathComponentā to sort by folder name and file name.
set theDescriptor to current application's NSSortDescriptor's sortDescriptorWithKey:"path" ascending:true selector:"localizedStandardCompare:"
theFiles's sortUsingDescriptors:{theDescriptor}
set theFolders to current application's NSMutableArray's new()
I tested the first script above with large and small folders. The timing results with this script and with a Finder script were:
LOCATION - FOLDERS - FILES - ASObjC RESULT - FINDER RESULT
External SSD - 5264 - 29312 - 995 milliseconds - 39 seconds
Internal SSD - 83 - 389 - 18 milliseconds - 565 milliseconds
The first script in this post was based on a script written by Shane and incorporates suggestions by Nigel and KniazidisR. Thanks for the help.