Get file.separator of a specified file path - java

How do you get a file separator of a specified file/folder path?
In Java, we can write, for example
File f = new File("C:\\MyFolder\\MyText.txt");
Keep in mind this is a file representation (the file does not have to exist physically). So given any specified path, is there a method that can return the separator for that specified path only?
From the docs
The File.pathSeparator and File.pathSeparatorChar returns system dependent file separator, but what I want is the separator for a given path, like in the above case \, even if the above program is run and the path is not valid for *nix

I would start with System.getProperty("user.home"). And, you could use File.seperator like
File f = new File(System.getProperty("user.home") +
File.seperator + "MyText.txt");
but I would prefer File(String parent, String child) like
File f = new File(System.getProperty("user.home"), "MyText.txt");
System.out.println(f.getPath());

The separator character for File objects is always given by File.separator (or File.separatorChar). There is no way to construct a File object with an unusual separator; they always hold paths that are valid on the current system.
File f = new File("C:\\MyFolder\\MyText.txt");
After executing this line on Windows, f refers to a File object that refers to the file MyText.txt in the folder MyFolder on drive C:, as you probably intended.
But on Linux, f refers to a File object that refers to the file C:\MyFolder\MyText.txt in the current directory. (On Linux, backslashes are allowed in filenames)
Imagine if there was a way to do this. If you had a File constructed with new File("a/b\\c"), then how would you know whether it was referring to the file b\c in the folder a (with separator /), or the file c in the folder a/b (with separator \)?
It can't, so it should be clear that there is no reliable way to do this. If your program handles paths with unusual separators, then your program needs to handle them itself. File cannot do it for you.

Related

getName() returns the old name of the file even if renameTo() has succeeded [duplicate]

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. So
String name = f.getName(); // gets the name without the directory
should likely be:
String name = f.getAbsolutePath();
(your search/replace may need to change)
The problem is that f.getName() returns the last name component of the path that is represented by f. You then massage this String and turn it back into a File. But the File 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 the dirName 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, the f objects are the pathnames for file system objects (either files or folders) in the directory denoted by the String dirname. Each of these f objects will have a directory part.
There is more than one way to fix your code; for example
change name = f.getName() to name = f.toString()
change new File(subbedName) to new 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 converting f 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:
File name charset problem in java
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4733494 (Note that Sun decided this was not a Java bug, and most of the "me too" comments on the bug report are from people who do not understand the explanation ...)
f.getName(); only returns the name of the folder, not the full path. So subbedName becomes a relative path file. Try something with f.getCanonicalPath() instead.

Why is directory name which contains dot(s) in the end is treated as a directory even if doesn't exists using File object in Java?

I have a directory which contains several files and directories. I am writing a small java program which displays the files present in a the directory supplied as a parameter.
The problem I am facing is when I append dot(s) after a directory name, it is being treated as existing even if the directory is not present. To further clarify, suppose I have a directory named "abc" which exists. It works fine when I enter "abc". But when I enter the directory name as "abc...", even then also the directory is being treated as it exists. I want to avoid it. I am creating a FIle object using
File directory = new File( fileName );
if ( directory.exists() ) {
// do something
}
Any suggestions how can I avoid it?
This is unrelated to Java, it's a Windows thing: Trailing dot(s) are removed from file and folder names. Even C/C++ programs can't do it.
As a workaround, try to use the prefix \\?\:
File dir = new File( "\\\\?\\" + path );
But this will disable a lot of other things like relative paths and slash conversion.
Related answers:
How to create a filename with a trailing period in Windows?
MSDN Naming Files, Paths, and Namespaces
Why doesn't Explorer let you create a file whose name begins with a dot?

How to rename file in a general way in java?

I have two File Object oldFile and newFile and I would like to exchange the corresponding file names. So I rename oldFile to a tmpFile name first. I get the oldFile's absolute path and append ".bak" for it:
String tmpFile = oldFile.getAbsolutePath().toString()+".bak";
oldFile.renameTo(new File(tmpFile));
The problem is that tmpFile contains the raw string of path,while the constructor of File class treat the '\' as the escape.So the tmpFile may be "D:\oldfile.java.bak",however what the constructor need is
new File("D:\\oldfile.java.bak");
How can I deal with it?
The constructor of File does NOT treat \ as escape. You need to escape \ with \ in a string literal. The String literal "\\" contains a single character: '\'.
String path = "D:\\oldFile";
System.out.println(path); // prints D:\oldFile
File f = new File(path);
System.out.println(f.getAbsolutePath()); // prints D:\oldFile
You have to escape the escapes with .replace("\", "\\") but if you have to do that then realize you don't have to use \ on Windows. Java supports / just as fine and it doesn't have these problems. You can do replace("\", "/") and it works just as well.
You also need to read and understand how to create new files in Java. File.createNewFile() is required to be called. Just creating a File object with the constructor doesn't actual create a file on the filesystem nor does it guarantee that a file at that location exists.

Java can't get the path of a file that exists in the current directory

If a file exists in the same directory where a Java application is running and I create a File object for that file the Java File methods for the path of the file include the filename as well. Code and output are below.
If this was a bug in the JDK version I'm using someone would surely have seen it by now.
Why do File.getAbsolutePath() and File.getCanonicalPath() include the file name? The Javadocs indicate that the directory name should be returned.
import java.io.File;
import java.io.IOException;
public class DirectoryFromFile {
private void getDirectoryOfFile(String fileName) throws IOException{
File f = new File(fileName );
System.out.println("exists(): " + f.exists());
System.out.println("getPath(): " + f.getPath());
System.out.println("getAbsolutePath(): " + f.getAbsolutePath());
System.out.println("getParent(): " + f.getParent() );
System.out.println("getCanonicalPath(): " + f.getCanonicalPath() );
System.out.println("getAbsoluteFile().getCanonicalPath(): " + f.getAbsoluteFile().getCanonicalPath() );
String dirname = f.getCanonicalPath();
System.out.println("dirname: " + dirname);
File dir = new File(dirname);
System.out.println("dir: " + dir.getAbsolutePath());
if (dirname.endsWith(fileName))
dirname = dirname.substring(0, dirname.length() - fileName.length());
System.out.println("dirname: " + dirname);
File dir2 = new File(dirname);
System.out.println("dir2: " + dir2.getAbsolutePath());
}
public static void main(String[] args) {
DirectoryFromFile dff = new DirectoryFromFile();
try {
dff.getDirectoryOfFile("test.txt");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Here' the output:
exists(): true
getPath(): test.txt
getAbsolutePath(): C:\dean\src\java\directorytest\directory.from.file\test.txt
getParent(): null
getCanonicalPath(): C:\dean\src\java\directorytest\directory.from.file\test.txt
getAbsoluteFile().getCanonicalPath(): C:\dean\src\java\directorytest\directory.from.file\test.txt
dirname: C:\dean\src\java\directorytest\directory.from.file\test.txt
dir: C:\dean\src\java\directorytest\directory.from.file\test.txt
dirname: C:\dean\src\java\directorytest\directory.from.file\
dir2: C:\dean\src\java\directorytest\directory.from.file
So far the only way I've found to get the directory in this case is to manually parse off the file name.
Does the File class have a way to get the directory name in this case (where a File that exists in the current directory is created without specifying a directory)?
Why do File.getAbsolutePath() and File.getCanonicalPath() include the
file name? The Javadocs indicate that the directory name should be
returned.
No, they don't. If you'd care to point out why you think they do, someone can probably identify the mistake in your reasoning. Also, if you specify exactly what you'd like to see for output given some particular input, we can help you out there, too. Your question title seems strange, too, since your problem seems to be that it is returning the full path to a file.
Edit: I think I understand the source of your confusion. A File represents a file system path in a platform-agnostic way. It can be a path to a file or to a directory. It also always represents the same path, though not necessarily the same absolute path. This is a very fine distinction but a very important one. A File object representing a relative path is always relative. Given a File representing a relative path, you can get the current corresponding absolute path using getAbsolutePath(). This doesn't, however, alter the fact that the File represents a relative path. Further invocations of getAbsolutePath() on the same File object may return different values. Consider, for example:
// A relative file
File foo = new File("foo.txt");
// Resolve relative file against CWD
System.out.println(foo.getAbsolutePath());
// Output: D:\dev\projects\testbed\foo.txt
System.setProperty("user.dir", "C:\\somewhere");
// Resolve relative file against new CWD
System.out.println(foo.getAbsolutePath());
// Output: C:\somewhere\foo.txt
// Get an absolute file
File absoluteFoo = foo.getAbsoluteFile();
// Show absolute path
System.out.println(absoluteFoo.getAbsolutePath());
// Output: C:\somewhere\foo.txt
System.setProperty("user.dir", "D:\\somewhere-else");
// An absolute path doesn't change when the CWD changes
System.out.println(absoluteFoo.getAbsolutePath());
// Output: C:\somewhere\foo.txt
It should be clear now that the path a File represents is only that: a path. Further, a path can be composed of zero or more parts, and calling getParent() on any File gives back the path of that File with the last path element removed unless there isn't a "last path element" to remove. Thus the expected result of new File("foo").getParent() is null since the relative path "foo" has no parent.
From the example and explanation above, you should be able to see that the way to get the containing directory when you've created relative-path File object is with
String absoluteParentDirPath = someRelativeFile.getAbsoluteFile().getParent();
with the caveat that the "absolute path" depends on your environment at the time.
Additional note: Since File is Serializable, you could write a relative-path file to disk or send it across a network. That File, when deserialized in another JVM, will still represent a relative path and will be resolved against whatever the current working directory of that JVM happens to be.
The behaviour is expected. The documentation does not mention that the filename is not included.
Perhaps you are confused by the difference between getAbsolutePath() and getAbsoluteFile(). It's that the latter returns a File instance.
I'm not sure why you think the Javadoc says that it returns the directory name.
Here is the Javadoc --
An abstract representation of file and directory pathnames.
User interfaces and operating systems use system-dependent pathname strings to name files and directories. This class presents an abstract, system-independent view of hierarchical pathnames. An abstract pathname has two components:
An optional system-dependent prefix string, such as a disk-drive specifier, "/" for the UNIX root directory, or "\\" for a Microsoft Windows UNC pathname, and
A sequence of zero or more string names.
The first name in an abstract pathname may be a directory name or, in the case of Microsoft Windows UNC pathnames, a hostname. Each subsequent name in an abstract pathname denotes a directory; the last name may denote either a directory or a file. The empty abstract pathname has no prefix and an empty name sequence.
http://download.oracle.com/javase/6/docs/api/java/io/File.html#getAbsolutePath%28%29
Returns the absolute pathname string of this abstract pathname.
In addition to the existing answers with regards to getAbsolutePath and getCanonicalPath, please also note, that File.getParent() does not mean "parent directory" it merely refers to the parent file object that was used to create the file.
For example, if the file object can be created as such:
File dir = new File("/path/to/a/directory");
File f1 = new File(dir, "x.txt");
File f2 = new File(dir, "../another/y.txt");
File f3 = new File("z.txt");
f1 would refer to /path/to/a/directory/x.txt, it's parent is dir (/path/to/a/directory)
f2 would refer to /path/to/a/directory/../another/y.txt, it's canonical path would be /path/to/a/another/y.txt, but it's parent is still the reference to dir (/path/to/a/directory)
f3 would refer to z.txt in the current directory. It does not have a parent file object, so f3.getParent() or f3.getParentFile() would return null.
path is the full path
if you only want the directory you need to call file.getParent()

Find Path During Runtime To Delete File

The code basically allows the user to input the name of the file that they would like to delete which is held in the variable 'catName' and then the following code is executed to try and find the path of the file and delete it. However, it doesn't seem to work, as it won't delete the file this way. Is does however delete the file if I input the whole path.
File file = new File(catName + ".txt");
String path = file.getCanonicalPath();
File filePath = new File(path);
filePath.delete();
If you're deleting files in the same directory that the program is executing in, you don't need specify a path, but if it's not in the same directory that your program is running in and you're expecting the program to know what directory your file is in, that's not going to happen.
Regarding your code above: the following examples all do the same thing. Let's assume your path is /home/kim/files and that's where you executed the program.
// deletes /home/kim/files/somefile.txt
boolean result = new File("somefile.txt").delete();
// deletes /home/kim/files/somefile.txt
File f = new File("somefile.txt");
boolean result = new File(f.getCanonicalPath()).delete();
// deletes /home/kim/files/somefile.txt
String execPath = System.getProperty("user.dir");
File f = new File(execPath+"/somefile.txt");
f.delete();
In other words, you'll need to specify the path where the deletable files are located. If they are located in different and changing locations, then you'll have to implement a search of your filesystem for the file, which could take a long time if it's a big filesystem. Here's an article on how to implement that.
Depending on what file you want to delete, and where it is stored, chances are that you are expecting Java to magically find the file.
String catName = 'test'
File file = new File(catName + '.txt');
If the program is running in say C:\TestProg\, then the File object is pointing to a file in the location C:\TestProg\test.txt. Since the file object is more of just a helper, it has no issues with pointing to a non-existent file (File can be used to create new files).
If you are trying to delete a file that is in a specific location, then you need to prepend the folder name to the file path, either canonically, or relative to the execution location.
String catName = 'test'
File file = new File('myfiles\\'+ catName +'.txt');
Now file is looking in C:\TestProg\myfiles\test.txt.
If you want to find that file anywhere, then you need a recursive search algorithm, that will traverse the filesystem.
The piece of code that you provided could be compacted to this:
boolean success = new File(catName + ".txt").delete();
The success variable will be true if the deletion was successful. If you do not provide the full absolute path (e.g. C:\Temp\test for the C:\Temp\test.txt file), your program will assume that the path is relative to its current working directory - typically the directory from where it was launched.
You should either provide an absolute path, or a path relative to the current directory. Your program will not try to find the file to delete anywhere else.

Categories