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
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.
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.
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”.
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
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:
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.
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
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.
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.