Faster way to select files with certain extension?

I have a script:


tell application "Finder"
set fileList to (every file of folder "Submissions" of disk "Wilbur" whose name extension is "docx")
end tell

There are hundreds of files in this folder of various types (PDF, Excel, etc).

This script to select files with a certain extension takes 30+ seconds to run! Is there a faster way to select files with a specific extension?

The following is faster. I tested it with PDF files but you can change that to whatever you want. The timing result with a folder that contained 330 files was 128 milliseconds.

use framework "AppKit"
use framework "Foundation"
use scripting additions

set theFileExtensions to {"pdf"}
set theFolder to POSIX path of (choose folder)
set theFiles to getFiles(theFolder, theFileExtensions)
current application's NSWorkspace's sharedWorkspace()'s activateFileViewerSelectingURLs:theFiles

on getFiles(theFolder, theExtensions)
	set fileManager to current application's NSFileManager's defaultManager()
	set theFolder to current application's |NSURL|'s fileURLWithPath:theFolder
	set theOption to (current application's NSDirectoryEnumerationSkipsHiddenFiles as integer)
	set theFiles to (fileManager's contentsOfDirectoryAtURL:theFolder includingPropertiesForKeys:{} options:theOption |error|:(missing value))
	set thePredicate to current application's NSPredicate's predicateWithFormat_("pathExtension.lowercaseString IN %@", theExtensions)
	return theFiles's filteredArrayUsingPredicate:thePredicate
end getFiles

activate
set nameExtension to text returned of (display dialog ¬
	"Search For Files Wih The Following Extension..." default answer ¬
	".docx" buttons {"Cancel", "Search"} default button 2 cancel button 1 ¬
	with title "Extension Search")

activate
set searchFolder to quoted form of POSIX path of ¬
	(choose folder with prompt "Choose Folder For Searching")

set theFiles to paragraphs of (do shell script "find " & searchFolder & ¬
	" -maxdepth 1 -iname '*" & nameExtension & "' | tr -s '//'")

set theFilesAsText to {}

repeat with i from 1 to count of theFiles
	try
		set theResult to POSIX file (item i of theFiles) as text
		set end of theFilesAsText to theResult
	end try
end repeat

tell application "Finder"
	select theFilesAsText
	activate
end tell

On second reading, I’m not certain I understand the OP’s request. The following script returns a list of files with the specified extension in the target folder. The timing result with my test folder of 330 files was 12 milliseconds; this assumes that the required frameworks are in memory, which would often be the case.

use framework "AppKit"
use framework "Foundation"
use scripting additions

set theFileExtensions to {"pdf"}
set theFolder to POSIX path of (choose folder)
set theFiles to getFiles(theFolder, theFileExtensions)

on getFiles(theFolder, theExtensions)
	set fileManager to current application's NSFileManager's defaultManager()
	set theFolder to current application's |NSURL|'s fileURLWithPath:theFolder
	set theOption to (current application's NSDirectoryEnumerationSkipsHiddenFiles as integer)
	set theFiles to (fileManager's contentsOfDirectoryAtURL:theFolder includingPropertiesForKeys:{} options:theOption |error|:(missing value))
	set thePredicate to current application's NSPredicate's predicateWithFormat_("pathExtension.lowercaseString IN %@", theExtensions)
	return ((theFiles's filteredArrayUsingPredicate:thePredicate) as list)
end getFiles

I used peavine’s approach here. Works great!

Thanks!

nigelheinsius. I’m glad the script worked well.

For my own use, I modified the script to select all files in a Finder window that have the same extension as a selected file and thought I would post it here FWIW. To test this script, simply select one file in a Finder window and run the script. I intentionally excluded any dialog notification of errors, although this is easily changed.

-- Revised 2021.12.06

use framework "Foundation"
use scripting additions

on main()
	tell application "Finder" to set theFile to selection as alias list
	if (count theFile) ≠ 1 then error number -128
	set theFile to current application's |NSURL|'s fileURLWithPath:(POSIX path of item 1 of theFile)
	set fileFolder to theFile's URLByDeletingLastPathComponent
	set fileExtension to theFile's pathExtension()
	if (fileExtension's isEqual:"") as boolean then error number -128
	set theFiles to getFiles(fileFolder, fileExtension)
	if (count theFiles) = 1 then error number -128
	tell application "Finder" to set selection to theFiles
end main

on getFiles(theFolder, theExtension)
	set fileManager to current application's NSFileManager's defaultManager()
	set theOption to (current application's NSDirectoryEnumerationSkipsHiddenFiles as integer)
	set theFiles to (fileManager's contentsOfDirectoryAtURL:theFolder includingPropertiesForKeys:{} options:theOption |error|:(missing value))
	set thePredicate to current application's NSPredicate's predicateWithFormat_("pathExtension.lowercaseString == %@", theExtension)
	return ((theFiles's filteredArrayUsingPredicate:thePredicate) as list)
end getFiles

main()

That is a cool script, thank you.

For those not comfortable with a lot of ASObjC scripting, below is a version using Shane’s FileManagerLib library.


use script "FileManagerLib" version "2.3.5"
use scripting additions

on main()
	tell application "Finder" to set theFile to selection as alias list
	if (count theFile) ≠ 1 then error number -128
	set {theExtension, theFolder} to {name_extension, parent_folder_path} of (parse object theFile)
	set theFiles to getFiles(theFolder, theExtension)
	tell application "Finder" to set the selection to theFiles
end main

on getFiles(theFolder, theExtension)
	
	set filesInFolder to objects of theFolder result type files list without searching subfolders and include folders
	set theFiles to {}
	repeat with thisFile in filesInFolder
		if name_extension of (parse object thisFile) is theExtension then set the end of theFiles to thisFile as item
	end repeat
	return theFiles
end getFiles

main()