Finding the file with the most recent "date modified"

HI folks.

Just wondering how I can find the file in a directory, with the most recent “date modified”. Currently I have the following, but I don’t think it’s going to work as files are created and updated at various times.

tell application "System Events"
	set the_file to the last file of folder holder_folder
end tell

Your script returns a value but we don’t know which criterium is applied to define the last file.

I dislike the Finder but for this task, I would use it.

set theFolder to choose folder
tell application "Finder" to tell folder theFolder
	set sortedList to sort every file by modification date
	
	set {firstItem, lastItem} to {item 1 of sortedList as alias, item -1 of sortedList as alias}
	# As Invisible files are visibles on my machine I added an extraneous instruction
	if name of lastItem is ".DS_Store" then set lastItem to item -2 of sortedList as alias
end tell
lastItem

With a bit of luck, Shane Stanley will post a more efficient code using ASObjC.

Yvan KOENIG running Yosemite 10.10.4 in French (VALLAURIS, France) mercredi 12 août 2015 19:14:18

Hi,

the Finder has a sort function


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

No-one will use because it’s significantly longer code:

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
	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
	-- get the path of the first item
	return ((theInfoNSMutableArray's objectAtIndex:0)'s valueForKey:(current application's NSURLPathKey)) as text -- extract path and convert to text
end mostRecentlyModifiedIemIn:

In my tests, that takes about 1/40th of the Finder equivalent.

Thanks Shane

What’s the problem ?
When we have the code available in a bank of handlers, its length doesn’t matter.
Copy Paste inserts it in the real script in a snap.

I’m just wondering upon the way your script drops .DS_Store.
On my machine this file is visible and is the more recently modified but happily it’s not the one returned.
StephanK’s one returns this generally hidden file as the last modified one.

Yvan KOENIG running Yosemite 10.10.4 in French (VALLAURIS, France) jeudi 13 août 2015 10:26:11

Yvan,

the Finder terminology considers the preference key AppleShowAllFiles which is (supposed to be) set to false by default.

Shane’s script skips hiiden files by passing the option NSDirectoryEnumerationSkipsHiddenFiles

If I throw in as alias list I seem to get slightly quicker results, or am I just imagining it?


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 indeed faster because the overhead to create the Finder object descriptor chain (file . of folder . of folder . of startup disk) can be omitted

Thanks for the confirmation and explanation Stefan.
Following one of your posts ages ago I tend to always throw in as alias list when getting a file list like that.

Thanks

It seems that I must understand that NSDirectoryEnumerationSkipsHiddenFile filter files whose name starts with “.” even when they aren’t hidden. It’s not the Finder’s behavior.
On my mac, “hidden files” are always visible so I took care of .DS_Store in my original answer.
Maybe it would be better to filter every file whose name starts with a dot.

Yvan KOENIG running Yosemite 10.10.4 in French (VALLAURIS, France) jeudi 13 août 2015 12:25:31

To make it clear this is the behavior of the usual ways to list files in the file system.

System Events displays always all files including hidden files.
Cocoa displays all files including hidden files unless you set the option NSDirectoryEnumerationSkipsHiddenFiles
Finder displays hidden files depending on the preference key AppleShowAllFiles

System Events and Cocoa don’t consider the Finder preference at all.

I guess that 95% of the users have AppleShowAllFiles set to the default value, false.

Not at all. Putting it in, the ASObjC version is only about 16 times faster, compared with 40 times faster otherwise.

As Stefan said, the Finder takes the Finder’s settings into account. I don’t think anything else does; for example, choose file has its own parameter for whether to include invisible files.

A minor thing: NSDirectoryEnumerationSkipsHiddenFiles skips files where the name begins with “.”, plus files that have the hidden attribute (NSURLIsHiddenKey) set.

Better still, put it in a library. But I think there’s still a strong perception that more code = slower. Particularly in a language with the performance peculiarities of AppleScript, there’s rarely much correlation.

Oh very good. That’s what I was looking for. I knew there was a way to target it.

Cheers. Works like a charm.

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