csv -rename files in a folder

I’m trying to adapt this script to rename some pdfs in a folder on my desktop using a csv file. Example the csv contains:
oldFileName newFileName
file-a-019.pdf file-b-018.pdf
file-a-020.pdf file-b-019.pdf
file-a-038.pdf file-b-047.pdf
file-a-039.pdf file-b-041.pdf
file-a-040.pdf file-b-043.pdf
file-a-041.pdf file-b-040.pdf
file-a-043.pdf file-b-044.pdf
file-a-044.pdf file-b-045.pdf

I’m getting an error number -1728 from file “oldFileName” of folder “Users/blanca-nives/Desktop/renameFiles”
Thank you for your help.

.

set theCSVData to paragraphs of (read "Users/blanca-nives/Desktop/Book1.csv")

set {oldTID, my text item delimiters} to {my text item delimiters, ","}
repeat with thisLine in theCSVData
	set {oldFileName, newFileName} to text items of thisLine
	tell application "System Events"
		try
			-->rename on the same folder where the originals are located
			set name of file oldFileName of folder "Users/blanca-nives/Desktop/renameFiles" to newFileName
		end try
		end tell
end repeat
set my text item delimiters to oldTID

Browser: Safari 537.36
Operating System: macOS 10.14

This works on Catalina.

set theFolder to (path to desktop as text) & "renameFiles:"
set csvFile to (path to desktop as text) & "Book1.csv"

set theCSVData to paragraphs of (read file csvFile)

set {oldTID, text item delimiters} to {text item delimiters, ","}

repeat with thisLine in theCSVData
	if thisLine > "" then
		-- if thisLine begins with "file" then -- alternative to preceding line
		set {oldFileName, newFileName} to text items of thisLine
		tell application "System Events"
			try
				set name of file (theFolder & oldFileName) to newFileName
			on error errorMessage
				display dialog errorMessage buttons "OK" cancel button 1 default button 1
			end try
		end tell
	end if
end repeat

set text item delimiters to oldTID

Hi!
Since the 1st line of the CSV file is actually “OldFileName” and you probably don’t have such a file in the folder you’re tagetting it throws an error.
You’d better skip the 1st line and start at line 2. HTH.

Wonderful. Thank you!:smiley:

Neat script I am finding useful thanks.

Is there anyway this script can be updated to preserve or ignore the file extensions so the original file extension is kept and not in the CSV file?

p_T. The following script does what you want. The name of the csv file is “Rename List.txt”. This script is more complicated then I would want–I’ll try to think of a simpler approach.

set theFolder to (choose folder) as text
set csvFile to theFolder & "Rename List.txt"
try
	set theCSVData to paragraphs of (read file csvFile)
on error
	display dialog "The csv file was not found" buttons {"OK"} cancel button 1 default button 1
end try

set {oldTID, text item delimiters} to {text item delimiters, ","}

set oldNames to {}
set newNames to {}
repeat with anItem in theCSVData
	if contents of anItem > "" then
		set end of oldNames to text item 1 of anItem
		set end of newNames to text item 2 of anItem
	end if
end repeat

set theCount to (count theCSVData)
set theCounter to 0
tell application "Finder"
	set theFiles to every file in folder theFolder as alias list
	repeat with aFile in theFiles
		try
			set fileName to name of aFile
			set fileExtension to name extension of aFile
			set baseName to text 1 thru -((count fileExtension) + 2) of fileName
			if baseName is in oldNames then
				repeat with i from 1 to theCount
					if baseName is equal to item i of oldNames then
						set name of aFile to ((item i of newNames) & "." & fileExtension)
						set theCounter to theCounter + 1
						exit repeat
					end if
				end repeat
			end if
		end try
	end repeat
end tell

set text item delimiters to oldTID

display dialog (theCounter as text) & " files were renamed" buttons {"OK"} default button 1

I tested this with the following csv file on my Sonoma computer, and it worked as expected. The first name is the old name and the second name is the new name. A file is skipped if it cannot be renamed because the target file already exists.

file-one,file-1
file-two,file-2
file-three,file-3
file four,file 4

Please test on file copies first.

Thanks @peavine its working well.

Will be interested to see how you can make it simpler.

Out of curiosity, how many files is this script processing at a time?
The Finder is not a good way to do file manipulations on larger file counts.
It is better to use “System Events”.

Just my opinion

I decided to go with speed instead of simplicity. When four files are renamed, my earlier script took 65 milliseconds and the following script took 2 milliseconds (with the Foundation framework in memory). A few comments:

  • Please test with file copies.
  • The getFiles handler is not recursive but is easily made so.
  • Package files are skipped.
  • The file-exists error message is a bit lame but is easily changed to whatever is desired.
use framework "Foundation"
use scripting additions

on main()
	set theFolder to POSIX path of (choose folder)
	set renameFile to theFolder & "Rename List.txt"
	set renameString to current application's NSMutableString's stringWithContentsOfFile:renameFile encoding:(current application's NSUTF8StringEncoding) |error|:(missing value)
	if renameString is (missing value) then display dialog "The CSV file was not found" buttons {"OK"} cancel button 1 default button 1
	set oldNames to renameString's stringByReplacingOccurrencesOfString:"(?m)^(.*),.*$" withString:"$1" options:1024 range:{0, renameString's |length|()} -- option 1024 enables regex
	set oldNames to (oldNames's componentsSeparatedByString:linefeed)
	set newNames to renameString's stringByReplacingOccurrencesOfString:"(?m)^.*,(.*)$" withString:"$1" options:1024 range:{0, renameString's |length|()}
	set newNames to (newNames's componentsSeparatedByString:linefeed)
	set theFiles to getFiles(theFolder)
	set theCounter to 0
	set fileManager to current application's NSFileManager's defaultManager()
	repeat with aFile in theFiles
		set fileName to (aFile's URLByDeletingPathExtension())'s lastPathComponent()
		if (oldNames's containsObject:fileName) is true then
			set theIndex to (oldNames's indexOfObject:fileName)
			set newName to (newNames's objectAtIndex:theIndex)
			if (newName's isEqualToString:"") is false then
				set fileFolder to aFile's URLByDeletingLastPathComponent()
				set fileExtension to aFile's pathExtension()
				set newFile to ((fileFolder's URLByAppendingPathComponent:newName)'s URLByAppendingPathExtension:fileExtension)
				set {theResult, theError} to (fileManager's moveItemAtURL:aFile toURL:newFile |error|:(reference))
				if (theResult as boolean) is false then
					display dialog (theError's localizedDescription() as text)
					set theCounter to theCounter - 1
				end if
				set theCounter to theCounter + 1
			end if
		end if
	end repeat
	display dialog (theCounter as text) & " files were renamed" buttons {"OK"} default button 1
end main

on getFiles(theFolder)
	set fileManager to current application's NSFileManager's defaultManager()
	set theFolder to current application's |NSURL|'s fileURLWithPath:theFolder
	set theKey to current application's NSURLIsRegularFileKey
	set theFiles to fileManager's contentsOfDirectoryAtURL:theFolder includingPropertiesForKeys:{theKey} options:4 |error|:(missing value)
	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
	return theFiles
end getFiles

main()

Robert. My test was with four files, and the timing result was 65 milliseconds. This is not terrible, but with a large number of files the script could become almost unusable. I’m sure the Finder slowed performance, but I suspect the repeat loops also contributed to this poor result. Both of these issues are avoided in my ASObjC script above.

Here is my cleaned up version using “System Events”

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

set theFolder to (choose folder) as text
set csvFile to theFolder & "Rename List.txt"
try
	set theCSVData to paragraphs of (read file csvFile)
on error
	display dialog "The csv file was not found" buttons {"OK"} cancel button 1 default button 1
end try

set {oldTID, text item delimiters} to {text item delimiters, {", ", ","}}

set oldNames to {}
set newNames to {}
repeat with anItem in theCSVData
	if contents of anItem > "" then
		set end of oldNames to text item 1 of anItem
		set end of newNames to text item 2 of anItem
	end if
end repeat

set theCount to (count theCSVData)
set theCounter to 0
tell application "System Events"
	repeat with i from 1 to theCount
		set fileName to item i of oldNames
		try
			set aFile to file fileName in folder theFolder
			set name of aFile to item i of newNames
			set theCounter to theCounter + 1
		end try
	end repeat
end tell

set text item delimiters to oldTID

display dialog (theCounter as text) & " files were renamed" buttons {"OK"} default button 1

Let me know how fast it is for you Peavine?

Robert. Your script returns an error at the following line:

set aFile to file fileName in folder theFolder --> System Events got an error: Can’t get file "file-one" of folder "Macintosh HD:Users:Robert:Downloads:".

BTW, the following are my four test file names, which are in my Downloads folder:

file four.pdf
file-one.png
file-three.txt
file-two.pdf

The test csvFile text is:

file-one,file-1
file-two,file-2
file-three,file-3
file four,file 4

Weird, it works for me,
and seeing that it is inside a try block, it shouldn’t show any error at all

Robert. In my testing, your script did not rename any files, so I disabled the try statement for testing purposes. That’s when I got the error message.

Your script works if I modify the CSV file as shown below, but forum member p_T stated that he wanted to ignore the file extensions in the CSV file. Also, if the CSV file specifies file extensions, then my script in post 2 in this thread can be used.

file-one.png,file-1.png
file-two.pdf,file-2.pdf
file-three.txt,file-3.txt
file four.pdf,file 4.pdf

AH. Im missed so much
Here is your script modified to use “System Events”

set theFolder to (choose folder) as text
set csvFile to theFolder & "Rename-List.txt"
try
	set theCSVData to paragraphs of (read file csvFile)
on error
	display dialog "The csv file was not found" buttons {"OK"} cancel button 1 default button 1
end try

set {oldTID, text item delimiters} to {text item delimiters, ","}

set oldNames to {}
set newNames to {}
repeat with anItem in theCSVData
	if contents of anItem > "" then
		set end of oldNames to text item 1 of anItem
		set end of newNames to text item 2 of anItem
	end if
end repeat

set theCount to (count theCSVData)
set theCounter to 0
tell application "System Events"
	set theFiles to {name, name extension} of files in folder theFolder --as alias list
end tell
repeat with i from 1 to count item 1 of theFiles
	try
		set fileName to item i of item 1 of theFiles
		set fileExtension to item i of item 2 of theFiles
		set baseName to text 1 thru -((count fileExtension) + 2) of fileName
		if baseName is in oldNames then
			repeat with i from 1 to theCount
				if baseName is equal to item i of oldNames then
					tell application "System Events"
						set name of (file fileName in folder theFolder) to ((item i of newNames) & "." & fileExtension)
					end tell
					set theCounter to theCounter + 1
					exit repeat
				end if
			end repeat
		end if
	end try
end repeat

set text item delimiters to oldTID

display dialog (theCounter as text) & " files were renamed" buttons {"OK"} default button 1
1 Like

Robert. I tested the script and the timing result was 7 milliseconds. I retested the Finder version and the timing result was 62 milliseconds. This was when renaming four files. I’m a bit surprised by the difference, as I thought all the repeat loops would slow the script. Perhaps getting the source file names and extensions up front instead of inside a repeat loop made a significant difference.

It also doesn’t use the Finder.
I always found the Finder to be much slower

My previous tests only renamed 4 files, which did not reflect the impact that the repeat loops would have on the timing results of the Finder and System Events scripts. I reran the tests with 100 files and got the following results:

SCRIPT - MILLISECONDS
ASOjbC - 37
System Events - 250
Finder - 808

BTW, I don’t think anyone is going to rename 100 files in this fashion, so the above is primarily of academic interest.

The shortcut included below is functionally equivalent to the scripts immediately above. The timing results were 100 milliseconds with 4 files and 1.36 second with 100 files, although, in actual use, the time it takes to rename 100 files seems significantly less.

Rename Files.shortcut (22.9 KB)

I think there’s an Applescript that comes w the Mac called “Replace Text in Item Names.” Don’t know if this will help