Finder vs System Events for returning contents of folder

i have a script where i’m currently using the command

tell application "Finder" to set folder_list to every item of entire contents of folder myFolder

which runs reasonably slow especially the longer the list is to return. The reason I use it is because it returns not only the contents of the folder but all of its subfolders as well.

I’ve been trying to use a version of the command with System Events because it runs so much faster, but I can’t figure out how to get it to return results from subfolders of the target folder

tell application "System Events" to set folder_list to the path of every disk item of folder myFolder

that is what i have so far. can anyone point me in the right direction to get results for subfolders?

What version of the OS are you running?

10.10.5

As you’ve found, the Finder is hopelessly slow. System Events doesn’t have an equivalent to entire contents, so you need to get all the items and recursively search each folder. It’s fairly tedious.

An alternative is to use AppleScriptObjC. It has the advantage of being much faster, although pre-10.11 you’ll get back a list of POSIX paths rather than files. So:

use scripting additions
use framework "Foundation"

on getItemsIn:posixPathOfFolder
	-- make URL
	set theNSURL to current application's class "NSURL"'s fileURLWithPath:posixPathOfFolder
	-- make file manager
	set theFileManager to current application's NSFileManager's new()
	-- get all except hidden items and items within packages
	set allURLs to (theFileManager's enumeratorAtURL:theNSURL includingPropertiesForKeys:{} options:((current application's NSDirectoryEnumerationSkipsPackageDescendants) + (current application's NSDirectoryEnumerationSkipsHiddenFiles as integer)) errorHandler:(missing value))'s allObjects()
	-- convert URLs to POSIX paths and coerce to list
	return (allURLs's valueForKey:"path") as list
end getItemsIn:

set posixPathOfFolder to POSIX path of (choose folder)
set listOfPaths to my getItemsIn:posixPathOfFolder

Thanks! that works great. I had also been tinkering with doing it with a shell script but that was returning all the paths as a big paragraph block that I then had to work with to get formatted nicely. That was a bit of a pain, this is much cleaner. Thanks again.

Shane, how would we specify a filter for the file list, like:
¢ file ext
¢ file type
¢ file name contains
¢ etc

Of course it would be great to allow for all of the folder search criteria that the Finder provides, but I assume that’s not practical.

Thanks.

Shane will certainly offer a more global answer but here is a script returning every .png and .jpeg / .jpg files.
Alas, the filter is case sensitive.

use scripting additions
use framework "Foundation"

on getItemsIn:posixPathOfFolder
	-- make URL
	set theNSURL to current application's class "NSURL"'s fileURLWithPath:posixPathOfFolder
	-- make file manager
	set theFileManager to current application's NSFileManager's new()
	-- get all except hidden items and items within packages
	set allURLs to (theFileManager's enumeratorAtURL:theNSURL includingPropertiesForKeys:{} options:((current application's NSDirectoryEnumerationSkipsPackageDescendants) + (current application's NSDirectoryEnumerationSkipsHiddenFiles as integer)) errorHandler:(missing value))'s allObjects()
	-- convert URLs to POSIX paths and coerce to list
	--return (allURLs's valueForKey:"path") as list # Original instruction
	set theArray to (allURLs's valueForKey:"path")
	set thePred to current application's NSPredicate's predicateWithFormat:"(self ENDSWITH '.jpg') OR (self ENDSWITH '.jpeg') OR (self ENDSWith '.png')"
	return (theArray's filteredArrayUsingPredicate:thePred) as list
end getItemsIn:

set posixPathOfFolder to POSIX path of (choose folder)
set listOfPaths to my getItemsIn:posixPathOfFolder

Yvan KOENIG running El Capitan 10.11.3 in French (VALLAURIS, France) samedi 27 février 2016 17:20:25

It’s worth reading up on predicates. As well as ENDSWITH, as Yvan used, there’s BEGINSWITH, CONTAINS, LIKE and MATCHES. They’re generally written in caps by convention, although they don’t have to be. For like, * and ? can be used as wildcards; match takes a regular expression pattern.

To ignore case, you insert “[c]”, as in “BEGINSWITH[c]”. Similarly, [cd] will ignore case and diacriticals.

Two other options are UTI-CONFORMS-TO and UTI-EQUALS.

As well as using self, which here means the full path, you can use lastPathComponent, which is the name, pathExtension for the extension, stringByDeletingLastPathComponent for the path to the parent folder, and stringByDeletingPathExtension.

Predicates are very cool…

Thanks Shane. I’m sure they are.
I’m trying to learn about 15 things right now, so this will have to wait.
I have a shell script solution – that will have to do for now.

I searched your book, but didn’t find much. Did I miss something?

Chapter 17 is an introduction, and there are a few other examples in there.

But I tend to look up the Predicate Programming Guide whenever I use them – you can’t memorize all this stuff.

Hello Shane.
As I missed the use of [c] in your script 17-1 (with a fever at 39°C), now that it’s 38°C I rwrote the instruction defining thepred as:

set thePred to current application’s NSPredicate’s predicateWithFormat:“(pathExtension like[c] ‘jpg’) OR (pathExtension like[c] ‘jpeg’) OR (pathExtension like[c] ‘png’)”

But maybe I missed also an other feature :

Is it posible to use type identifiers in a filter ?

Yvan KOENIG running El Capitan 10.11.3 in French (VALLAURIS, France) dimanche 28 février 2016 16:55:34

Not in a predicate, no. This is just string filtering.

Thanks Shane.

After scrapping my head reading the user guide I built a simpler syntax for the predicate :

set thePred to current application’s NSPredicate’s predicateWithFormat:“pathExtension IN[c] {‘jpg’, ‘jpeg’, ‘png’}”

This one is close to the clause used when we work with the Finder.

Yvan KOENIG running El Capitan 10.11.3 in French (VALLAURIS, France) lundi 29 février 2016 10:32:39

If you have the osax AppleScript Toolbox installed you can use AST list folder command:

AST list folder theFolder matching regex "\\.jp[e]?g$" with listing subfolders

Perfect!

Thanks Shane.

I tried to build a more versatile handler.

use scripting additions
use framework "Foundation"

on getItemsIn:posixPathOfFolder searchedExtensions:theList
	-- make URL
	set theNSURL to current application's class "NSURL"'s fileURLWithPath:posixPathOfFolder
	-- make file manager
	set theFileManager to current application's NSFileManager's new()
	-- get all except hidden items and items within packages
	set allURLs to (theFileManager's enumeratorAtURL:theNSURL includingPropertiesForKeys:{"path"} options:((current application's NSDirectoryEnumerationSkipsPackageDescendants) + (current application's NSDirectoryEnumerationSkipsHiddenFiles as integer)) errorHandler:(missing value))'s allObjects()
	set thePred to current application's NSPredicate's predicateWithFormat:"pathExtension IN[c] %@" argumentArray:{theList}
	set theURLs to allURLs's filteredArrayUsingPredicate:thePred
	-- convert URLs to POSIX paths 
	return (theURLs's valueForKey:"path") as list
end getItemsIn:searchedExtensions:

set posixPathOfFolder to POSIX path of (choose folder)
set listOfPaths to my getItemsIn:posixPathOfFolder searchedExtensions:{"jpg", "jpeg", "png"}

I’m wondering if it’s really a good idea to keep only the paths when building allURLs.
It eat cycles but I guess that the created objet becoming smaller, filtering it will be faster.

Yvan KOENIG running El Capitan 10.11.3 in French (VALLAURIS, France) lundi 29 février 2016 14:14:30

Yvan, many thanks for sharing this handler – makes it really user-friendly. 👍
Shane, many thanks again for sharing the basic ASObjC code. 👍

Really, the only way to answer questions like that is to make your own timings. My guess is it doesn’t make a lot of difference.

The other issue is what kind of result you want. If you’re on 10.11, you can skip changing to paths and when you coerce the URLs to a list they will become files (class furl»). Depending on what you’re doing, that might be more useful.