I'm trying to list a directory's contents, and rename certain files.
public void run(String dirName) {
try {
File parDir = new File(dirName);
File[] dirContents = parDir.listFiles();
// Rename if necessary
for(File f : dirContents) {
System.out.println("f is:\n" + f.toString());
String name = f.getName();
String subbedName = name.replaceAll("\uFFFD", "_");
System.out.println("\n" + "name = " + name + ", subbedName = " + subbedName + "\n");
if(!name.equals(subbedName)) {
File newFile = new File(f.getParentFile(), subbedName);
System.out.println("newFile is:\n" + newFile.toString());
if(!f.renameTo(newFile))
System.out.println("Tried to change file name but couldn't.");
}
}
}
catch(Exception exc1) {
System.out.println("Something happened while listing and renaming directory contents: " + exc1.getMessage());
}
}
When I run this, I get "Tried to change file name but couldn't.
" I don't believe that Java is considering these files to be "open", so I don't think that's the reason. I've even ran chmod 777 myDir
where myDir
is the value of the dirName
string passed into the run
method.
What am I missing here? Why won't Java rename these file(s)? These are CentOS machines.
Edit: Added printouts for both f
and newFile
, which is as follows:
f is:
/root/path/to/mydir/test�.txt
newFile is:
/root/path/to/mydir/test_.txt
You need to create your new
File
object with the full pathname of those files. Soshould likely be:
(your search/replace may need to change)
f.getName();
only returns the name of the folder, not the full path. SosubbedName
becomes a relative path file. Try something withf.getCanonicalPath()
instead.The problem is that
f.getName()
returns the last name component of the path that is represented byf
. You then massage this String and turn it back into aFile
. But theFile
now represents a path relative to the current directory, not the directory containing the original path.As a result your code is actually attempting to rename the files from
dirName
into the application's current directory. That could fail because files already exist in the current directory with those names, or because thedirName
and the current directory are in different file systems. (You cannot rename a file from one filesystem to another ... you have to copy it.)Please note that a
File
in Java represents a pathname, not a file or a folder. In your code, thef
objects are the pathnames for file system objects (either files or folders) in the directory denoted by the Stringdirname
. Each of thesef
objects will have a directory part.There is more than one way to fix your code; for example
name = f.getName()
toname = f.toString()
new File(subbedName)
tonew File(f.getParentFile(), subbedName)
I have an alternative / additional theory.
The pathname of the file containing the
\uFFFD
character is coming out as "mojibake"; i.e. the kind of garbled text that you get when you display encoded text using the wrong encoding. And since we are seeing 3 characters of garbled text, I suspect that it is attempting to display the UTF-8 rendering of\uFFFD
as Latin-1.So my theory is that the same think is happening when the
File.renameTo
method is convertingf
to the form that it is going to provide to the system call. For some reason that is no clear to me, Java could be using the wrong encoding, and as a result producing a "name" for the original file that doesn't match the name of the file in the file system. That would be sufficient to cause the rename to fail.Possibly related questions / links: