Finding the file with the most recent "date modified"

Out of interest try this variation to see a speed jump.


set theFolder to (choose folder) as text

tell application "Finder"
   set the_file to last item of (sort (get files of folder theFolder as alias list) by modification date)
end tell

It’s a little trick I learnt off Stefan.

Is it faster than :

set theFolder to (choose folder)

tell application "Finder"
	set the_file to last item of (sort (get files of theFolder as alias list) by modification date)
end tell

If you are interested by speed, I just wish to say that Shane Stanley gave a code which is 14 times faster than the “optimized” Finder version (40 times faster than the “non optimized” one).
It’s not because a script listing is shorter than an other one that it is faster.

Yvan KOENIG running Yosemite 10.10.5 in French (VALLAURIS, France) lundi 17 août 2015 11:01:04

Thanks Yvan.
Yeah, I understand it’s not because the code listing is shorter :wink:

Do we need ASObjC Runner present to get Shane’s code to work? I could compile it but when executed I got an error.

TIA

No need for ASObjC Runner, just running under Yosemite (or El Capitan)

Are you sure that you inserted the three instructions available at the beginning of Shane’s proposal ?
I ask that because the script compiles without them but of course it fails.
Without the 3 instructions the error message would be : class “NSURL” ne comprend pas le message « fileURLWithPath_ ».

Yvan KOENIG running Yosemite 10.10.5 in French (VALLAURIS, France) lundi 17 août 2015 12:05:07

P.S. In fact, we may also use it under Mavericks but in this case, the handler must be saved inas a library which must be “blessed” and stored in a dedicated location :
“/Library/Script Libraries/”
or
“~/Library/Script Libraries/”

Thanks for the info Yvan, think you may have nailed it in your P.S.

I’m on Mavericks, and I was getting the error ‘Can’t find framework “Foundation” of <>. Access not allowed.’

Please can you explain what you mean by ‘blessed’? Are you just talking about access privileges?

TIA

TecNik,

This gives a good explanation with screen shots:

macosxautomation.com/mavericks/libraries/asoc.html

There’s also a more detailed explanation here:

macscripter.net/viewtopic.php?id=41638

OK, I am not a sooth sayer so I can’t guess which operating system is used :wink:

Open the script in Script Editor
Save it as a “paquet de scripts” (I don’t know the exact wording in English)
On the top/right of the script’s window you will see an icon entitled “Contenu du paquet” (one more time, I don’t know the exact wording in English)
Click on it to reveal a pane which will appear on the right edge of the window.
It contain a checkbox entitled “AppleScript/Bibliothèque Objective-C” (I assume that it’s “AppleScript/Library Objective-C” in English)
Check it and resave the file.
Store it in one of the folder described in my late message.

After that, assuming that you named the library as mostRecentlyModifiedIemIn.scptd, you will be able to call it with :

use AppleScript version "2.3"
use theLib : script "mostRecentlyModifiedIemIn"
use scripting additions
use framework "Foundation"

set folderPosixPath to POSIX path of (choose folder)
set mostRecentlyModifiedIemIn to theLib's mostRecentlyModifiedIemIn:(folderPosixPath)

Yvan KOENIG running Yosemite 10.10.5 in French (VALLAURIS, France) lundi 17 août 2015 14:45:15

Hi Shane,

Thanks for the links.
I’ll have a dabble when I get chance, looks interesting.

:slight_smile:

I needed a quicker way than Finder to sort a folder’s files by modification date, which is why I found this thread. The folder has 400 files, and Finder varies, taking from about 6 to 11 seconds to sort it by mod date (“tell application ‘Finder’ to sort targetFolder by modification date”). Shane’s handler on this page, which I don’t understand, when modified for my needs (shown here), takes only about 3.5 seconds every time, to return a complete list of the 400 filenames. (I’m using a 2020 Macbook Air running Catalina). My way of doing this, as seen here, may be clumsy, but I don’t know enough to do any better. If anyone needs a list of all filenames in a folder sorted by modification date by Shane’s brilliant handler, this works better than using Finder. Thanks go to Shane.
–●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
–●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
–Shane’s original coding (on this page) modified to return a list of filenames sorted in mod order. Cut and paste everything below this line into Script Editor to use.
–●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
global countOfFolderPosixFile --the only way I know to get this variable into Shane’s handler (el7)
–●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
–Shane’s coding
use AppleScript version “2.7”
use scripting additions
use framework “Foundation”
–●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
set folderPosixPath to POSIX path of (choose folder) --file path for Shane’s handler below
set folderPosixFile to ((folderPosixPath as POSIX file) as string) --Mac file path for chosen folder (el7)
tell application “Finder” to set countOfFolderPosixFile to (count of (name of every file of (folderPosixFile as alias) as list)) as integer --# of files in chosen folder (el7)
–●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
–result of Shane’s handler starts with “its”. “its” seems both to invoke the handler and return its result, whereas in Applescript, with which I’m familiar, i’ve been doing the same thing the following way: “set myVariable to myHandler()” (el7 – hope I’m accurate about this)
set sortedFileNames to its mostRecentlyModifiedIemIn:folderPosixPath
–●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
–returns a carriage-return-delimited string of the list sorted paths returned by Shane’s handler (el7)
set AppleScript’s text item delimiters to (character id 10)
set sortedFileNames to text items of sortedFileNames as string
–●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
set stripFilePaths to (character id 10) & ((folderPosixPath as POSIX file) as string) --creating delimiter for applescript string, which sortedFileNames is now (el7)
–●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
–strips out all, except the first, path strings in sortedFileNames string (el7)
set AppleScript’s text item delimiters to stripFilePaths
set sortedFileNames to text items of sortedFileNames as list
–●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
set AppleScript’s text item delimiters to “”
tell application “Finder” to set item 1 of sortedFileNames to name of (item 1 of sortedFileNames as alias) --strips out the first and only path string remaining in sortedFileNames (el7)
–●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
sortedFileNames --the MdGuffin, a list of file names of the chosen folder in descending modification date order, sorted by Shane’s handler (el7)
–●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
–Shane’s handler, mostly, with his notes, which are about the only things i understand (el7)
on mostRecentlyModifiedIemIn:folderPosixPath
set theNSURL to current application’s class “NSURL”'s fileURLWithPath:folderPosixPath – make URL for folder because that’s what’s needed
set theNSFileManager to current application’s NSFileManager’s defaultManager() – get file manager
– get contents of the folder
set keysToRequest to {current application’s NSURLPathKey, current application’s NSURLContentModificationDateKey} – keys for values we want for each item
set theURLs to theNSFileManager’s contentsOfDirectoryAtURL:theNSURL includingPropertiesForKeys:keysToRequest options:(current application’s NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value)
– get mod dates and paths for URLs
set theInfoNSMutableArray to current application’s NSMutableArray’s array() – array to store new values in
repeat with i from 1 to theURLs’s |count|()
set anNSURL to (theURLs’s objectAtIndex:(i - 1)) – zero-based
(theInfoNSMutableArray’s addObject:(anNSURL’s resourceValuesForKeys:keysToRequest |error|:(missing value))) – get values dictionary and add to array
end repeat
– sort them in date order
set theNSSortDescriptor to current application’s NSSortDescriptor’s sortDescriptorWithKey:(current application’s NSURLContentModificationDateKey) ascending:false – describes the sort to perform
theInfoNSMutableArray’s sortUsingDescriptors:{theNSSortDescriptor} – do the sort
–●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
–build a list sorted by modification date by Shane’s handler, using AppleScript lingo with a key line of Shane’s (el7)
tell application “Finder”
set sortedFileNames to {} as list
repeat with i from 0 to countOfFolderPosixFile
((theInfoNSMutableArray’s objectAtIndex:(i))'s valueForKey:(current application’s NSURLPathKey)) as text – extract path and convert to text–Shane’s important line of code, with his “(0)'s” changed to my “(i)'s” in a repeat loop (el7)
set sortedFileNames to sortedFileNames & ((result as POSIX file) as string) as list
end repeat
return sortedFileNames --right here, all the heavy lifting is done (el7)
end tell
end mostRecentlyModifiedIemIn:
–end of modified coding
–●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
–●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●

Model: MacBook Air 2020, OS 10.15.7
AppleScript: 2.7
Browser: Safari
Operating System: Other

For a list in modification order, use this code. And don’t put it inside a Finder tell block.

use AppleScript version "2.3"
use scripting additions
use framework "Foundation"

set folderPosixPath to POSIX path of (choose folder)
its filesSortedByModDate:folderPosixPath

on filesSortedByModDate:folderPosixPath
	set theNSURL to current application's class "NSURL"'s fileURLWithPath:folderPosixPath -- make URL for folder because that's what's needed
	set theNSFileManager to current application's NSFileManager's defaultManager() -- get file manager
	-- get contents of the folder
	set keysToRequest to {current application's NSURLPathKey, current application's NSURLContentModificationDateKey} -- keys for values we want for each item
	set theURLs to theNSFileManager's contentsOfDirectoryAtURL:theNSURL includingPropertiesForKeys:keysToRequest options:(current application's NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value)
	-- get mod dates and paths for URLs
	set theInfoNSMutableArray to current application's NSMutableArray's array() -- array to store new values in
	repeat with oneURL in theURLs
		(theInfoNSMutableArray's addObject:(oneURL's resourceValuesForKeys:keysToRequest |error|:(missing value))) -- get values dictionary and add to array
	end repeat
	-- sort them in date order
	set theNSSortDescriptor to current application's NSSortDescriptor's sortDescriptorWithKey:(current application's NSURLContentModificationDateKey) ascending:false -- describes the sort to perform
	theInfoNSMutableArray's sortUsingDescriptors:{theNSSortDescriptor} -- do the sort
	-- get the path of the first item
	return (theInfoNSMutableArray's valueForKey:(current application's NSURLPathKey)) as list
end filesSortedByModDate:

You can take out the expermental (and apparently offensive) Finder tell block, and it still gives a result I need – to return not an empty list or a single file, but a list of just the names of all the files of a folder, sorted in mod date order. I don’t know if anyone needs to do this, but i posted it here just in case, because I couldn’t find a way to do it anywhere else, except with Finder, which is too slow for my needs. I needed this for a “choose from list” of these filenames, where the path of them already is known, and all those redundant paths obfuscate the necessary info.

It’s not offensive – it’s just that there’s a common misconception that because you’re dealing in files, you somehow have to involve the Finder, whereas often doing so is counter-productive. As a general rule, it’s a good aim to have only code relevant to an application inside that app’s tell block.

Just for fun, I created a whole vanilla AppleScript with a combSort

It get a folder with ~200 files using “System Events” instead of Finder and sorts it in .12 seconds

use AppleScript version "2.3"
use scripting additions

set theFolder to (choose folder) as text
tell application "System Events" --to tell folder theFolder
	set theFolder to folder theFolder
	set fileList to {path, modification date} of every file of theFolder --by modification date
end tell
set sortedList to {}
repeat with i from 1 to count (item 1 of fileList)
	set end of sortedList to {item i of item 1 of fileList, item i of item 2 of fileList}
end repeat
combSort(sortedList, 2)
get first item of sortedList

on combSort(nlist as list, sortitem)
	local i, j, cc, ns, gap, sf, sw -- ns means No Swap
	script M
		property alist : nlist
	end script
	set sf to 1.7 -- 1.3
	set cc to (count of M's alist)
	set gap to cc div sf
	repeat until gap = 0
		set ns to true
		repeat with i from 1 to (cc - gap)
			if (item sortitem of item i of M's alist) > (item sortitem of item (i + gap) of M's alist) then
				set sw to (item i of M's alist)
				set (item i of M's alist) to (item (i + gap) of M's alist)
				set (item (i + gap) of M's alist) to sw
				set ns to false
			end if
		end repeat
		if ns then set gap to gap div sf
	end repeat
end combSort

For those wanting a list of filenames sorted in mod date order–
Because of my ignorance, it took a lot of experimentation to try to adapt Shane’s great code to my needs, including putting in superflous Finder blocks to see what happens, which I forgot to take out before posting. Otherwise, if you notice, I invoke Finder only in the lines of code as needed. Even with reckless experimentation, I think I was lucky to get this far. Incidentally, when I paste Shane’s new code into sript editor, it’s not working out-of-the-box like my blemished version, which should have the blemish (Finder block) removed. I think I’m done with this thread.

Model: MacBook Air 2020, OS 10.15.7
AppleScript: 2.7
Browser: Safari
Operating System: Other

Did you notice how fast my plain Vanilla AppleScript was?

I just ran it on a folder with over 1000 items. It took .65 seconds

hey Shane, I have no skill in ObjC, but this below script return empty value.
My guess is that the last few lines should be like:

	-- sort them in date order
	set theNSSortDescriptor to current application's NSSortDescriptor's sortDescriptorWithKey:(current application's NSURLContentModificationDateKey) ascending:false -- describes the sort to perform
	theInfoNSMutableArray2's sortUsingDescriptors:{theNSSortDescriptor} -- do the sort
	-- get the path of the first item
	return (theInfoNSMutableArray2's valueForKey:(current application's NSURLPathKey)) as list

My again, I might be wrong …
L.

I also couldn’t get Shane’s script in post 25 to work. However, his script in post 4 works as expected and returns the most-recently modified file. I modified this script to return all files in a folder by modification date.

use AppleScript version "2.3"
use scripting additions
use framework "Foundation"

set folderPosixPath to POSIX path of (choose folder)

its mostRecentlyModifiedIemIn:folderPosixPath

on mostRecentlyModifiedIemIn:folderPosixPath -- the handler name should probably be changed
	set theNSURL to current application's class "NSURL"'s fileURLWithPath:folderPosixPath
	set theNSFileManager to current application's NSFileManager's defaultManager()
	set keysToRequest to {current application's NSURLPathKey, current application's NSURLContentModificationDateKey} -- keys for values we want for each item
	set theURLs to theNSFileManager's contentsOfDirectoryAtURL:theNSURL includingPropertiesForKeys:keysToRequest options:(current application's NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value)
	
	set theInfoNSMutableArray to current application's NSMutableArray's array()
	repeat with i from 1 to theURLs's |count|()
		set anNSURL to (theURLs's objectAtIndex:(i - 1))
		(theInfoNSMutableArray's addObject:(anNSURL's resourceValuesForKeys:keysToRequest |error|:(missing value)))
	end repeat
	
	set theNSSortDescriptor to current application's NSSortDescriptor's sortDescriptorWithKey:(current application's NSURLContentModificationDateKey) ascending:true -- describes the sort to perform
	theInfoNSMutableArray's sortUsingDescriptors:{theNSSortDescriptor} -- do the sort
	return (theInfoNSMutableArray's valueForKey:(current application's NSURLPathKey)) as list -- extract paths and convert to list (my modification)
end mostRecentlyModifiedIemIn:

OK, this is the ‘cheater’ way I accomplish this. Minimal code, plenty fast

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

set mylist to do shell script "cd ~/Downloads/; ls -t"  -- -t option sorts results by mod date
set recentFile to (path to downloads folder) & paragraph 1 of mylist as string

I ran some timing test on a number of the suggestions contained in this thread. I made minor modifications to the scripts so that they returned a list of all files sorted by modification date. The test folder contained 11 files.

The timing results were:

Finder in post 3 - 0.260 second (includes converting Finder references to HFS text)

ASObjC in post 4 - 0.023 second

System Events with combsort in post 28 - 0.012 second

Shell command in post 33 - 0.005 second

Hello Peavine,

Can you try your tests with a folder with ~400 items to see the difference between each method as the list gets bigger?

Just curious…

Thanks