Copy every nth file from a folder to a new folder

peavine: I tested the below code twice—once with a folder with 3460 files and then with a folder with 20K files; it was edited just a bit from your original to ensure the Finder didn’t start doing something else in between runs. The respective results were {13, 6} and {76,31}, indicating that using alias lists is about twice as fast on my machine around the few thousand mark and that the effect scales gradually higher in performance with larger counts. I tested this on a 2012 Mac Mini with a spinning HD formatted in HFS, which may be a factor.


set logTime to {}
tell application "Finder"
	set theFolder to folder -1 --the last created folder on my desktop
	set startTime to my (current date)'s time --my used to escape standard addition error
	get theFolder's files
	set logTime's end to (my (current date)'s time) - startTime
	delay 0.5
	set startTime to my (current date)'s time
	get theFolder's files as alias list
	set logTime's end to (my (current date)'s time) - startTime
end tell
logTime

Marc Anthony. I ran your script on my test folder of 20,000 text files and my results were {9, 19} compared with your result of {76. 31}. It does seem that part of the reason for this difference could be the hardware.

My computer is a 2018 Mac mini with A 6-core cpu and 16GB memory. The test files are on a APFS-formatted Samsung T5 external SSD, which has a read speed of about 540 MB/s.

Once again, apologies to the OP for going off-topic. I raised this issue as a simple question to Nigel and it sort of became more involved. If Nigel thinks these posts should be moved to another thread that would be great.

I wonder. I know that APFS does smart tricks when duplicating files, so if your folder is full of files you’ve made by duplicating then their contents haven’t actually been duplicated, but that’s just the contents.

I set up a folder of 4700 files. I ran Marc script, and I got {19, 16}. I have to say, this surprised me – I was expecting results more like Marc’s. (I tested on an iMac with Fusion Drive.)

But if I get the list using my FileManagerLib, it takes well under 1 second. So by definition, the time spent talking to hardware is a minute fraction overall. I suppose the Finder could be doing thousands of separate disk hits.

But I wonder if it’s some combination of OS version and APFS vs HFS.

Oooh! No. My apologies to you and KniazidisR. I was getting my wires crossed a little above when I mentioned replies being helpful to the OP.

While I feel that initial responses should be geared directly towards helping the OP — which includes offering code they’re likely to be able to understand given their apparent current knowledge of AppleScript (judging from what they post) — it’s perfectly reasonable for anyone who’s interested to go on to discuss improvements, other methods, and matters arising once the initial help’s been given. This is exactly what happened above and I’m sorry if I gave the impression that exploring alternative ways to achieve the same end was off-topic.

Nigel–thanks for the information. Sometimes there’s a fine line between hijacking a thread and adding information that could be helpful, and it was good to read your thoughts on this.

Hi all, I have tried some of your scripts for copying every 10th file from a folder containing around 40,000 files. It keeps giving me the error apple event timed out. Any suggestions?

I successfully tested the following script on my Sonoma computer with 5,000 files. I don’t know if it will work with 40,000 files. Please note:

  • The script gets all files in the source folder but not its subfolders.

  • Package files are skipped.

  • Before getting every tenth file, the source files are sorted by name in the same manner as the Finder.

  • If an existing file is found in the target folder, the user is notified and the file is skipped.

-- revised 2024.03.17

use framework "Foundation"
use scripting additions

on main()
	set sourceFolder to POSIX path of (choose folder with prompt "Select the source folder")
	set sourceFolder to current application's |NSURL|'s fileURLWithPath:sourceFolder
	set targetFolder to POSIX path of (choose folder with prompt "Select the destination folder")
	set targetFolder to current application's |NSURL|'s fileURLWithPath:targetFolder
	set sourceFiles to getSourceFiles(sourceFolder)
	copyFiles(sourceFiles, targetFolder)
end main

on getSourceFiles(theFolder)
	set fileManager to current application's NSFileManager's defaultManager()
	set theKey to current application's NSURLIsRegularFileKey -- does not include packages
	set theFiles to fileManager's contentsOfDirectoryAtURL:theFolder includingPropertiesForKeys:{theKey} options:4 |error|:(missing value) -- option 4 skips hidden files
	repeat with i from theFiles's |count|() to 1 by -1
		set anItem to (theFiles's objectAtIndex:(i - 1))
		set {theResult, regularFile} to (anItem's getResourceValue:(reference) forKey:theKey |error|:(missing value))
		if regularFile as boolean is false then (theFiles's removeObject:anItem)
	end repeat
	set theDescriptor to current application's NSSortDescriptor's sortDescriptorWithKey:"lastPathComponent" ascending:true selector:"localizedStandardCompare:" -- sorts in the same manner as the Finder
	(theFiles's sortUsingDescriptors:{theDescriptor})
	return theFiles
end getSourceFiles

on copyFiles(sourceFiles, targetFolder)
	set fileManager to current application's NSFileManager's defaultManager()
	set fileCount to sourceFiles's |count|()
	repeat with i from 1 to fileCount by 10
		set aFile to (sourceFiles's objectAtIndex:(i - 1))
		set fileName to aFile's lastPathComponent()
		set targetFile to (targetFolder's URLByAppendingPathComponent:fileName)
		set {theResult, theError} to (fileManager's copyItemAtURL:aFile toURL:targetFile |error|:(reference))
		if theResult is false then display alert "File " & quote & (fileName as text) & quote & " could not be copied" message "This often occurs when a file with this name already exists in the destination folder" buttons {"Cancel", "Skip"} cancel button 1
	end repeat
end copyFiles

main()