Java's relative path in class File - java

here is my code:
File file1 = new File("");
System.out.println(file1.exists()); // why the output is false?
System.out.println(file1.getAbsolutePath());
// assume that my current path is "d:/xxx/yyy"
File file2 = new File(".");
System.out.println(file2.getPath()); // i want to get ""
// but i actually get ".",
// which is not i want.
// so how can i get ""
to sum up, what i want is an object file of class File, which when i call
file.getPath() it returns ""
and when i call file.exists() it returns true;

If you really just want to have the current working directory in a string, you can simply use System.getProperty("user.dir"), see System Properties.
Otherwise you'll have to use . for the "current working directory" and use File#getCanonicalPath() the get the canonical representation of this File object. Also see File#getCanonicalFile().

To your first question: File("") is a valid path and is equivalent to System.getProperty("user.dir"). It is not a valid file or directory in that path (it still doea have a path though. This is a completely relative path, so when you call getPath() it will return an empty string since no file found by the name "".
Your second question "." is a directory, it exists, and it also has a relative path of "", so when calling getPath you will see the path "" + the directory name "."

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.

relative file path not working in Java

After reading that is it possible to create a relative filepath name using "../" I tried it out.
I have a relative path for a file set like this:
String dir = ".." + File.separator + "web" + File.separator + "main";
But when I try setting the file with the code below, I get a FileNotFoundException.
File nFile= new File(dir + File.separator + "new.txt");
Why is this?
nFile prints: "C:\dev\app\build\..\web\main"
and
("") file prints "C:\dev\app\build"
According to your outputs, after you enter build you go up 1 time with .. back to app and expect web to be there (in the same level as build). Make sure that the directory C:\dev\app\web\main exists.
You could use exists() to check whether the directory dir exist, if not create it using mkdirs()
Sample code:
File parent = new File(dir);
if(! parent.exists()) {
parents.mkdirs();
}
File nFile = new File(parent, "new.txt");
Note that it is possible that the file denoted by parent may already exist but is not a directory, in witch case it would not be possible to use it a s parent. The above code does not handle this case.
Why wont you take the Env-Varable "user.dir"?
It returns you the path, in which the application was started from.
System.getProperty(user.dir)+File.separator+"main"+File.separator+[and so on]

File returns always false for isDirectory and isFile in Java

Why file returns false for isFile() method, even when it is file. And when it is directory, it returns false for isDirectory(). Am I doing something wrong? These files/directories I test don't exists, and I need to create these, so that is why I am testing if I should use createFile() or mkdir().
File file = new File("C:/Users/John/Desktop/MyDir/file.txt");
if(!file.exists())
{
System.out.println("Is directory : " + file.isDirectory());
System.out.println("Is file : " + file.isFile());
}
In your if you're checking if the file doesn't exist. If it doesn't exist then it's neither a file nor a directory.
Java can't determine if your File object is a file or a directory only with a path string. The String could mean a file or a directory (you can have a folder named "file.txt" or a file with the same name).
What you are doing is saying if it doesn't exist. If it doesn't exist it is neither a file or directory. Your logic must be wrong as you should use:
if(file.exists()){
You're using isDirectory() and isFile() on a file object that doesn't exist. Both of these methods return false if the specified file does not exist yet, as per the documentation.
Your program only prints out if if(!file.exists()), which means that if the file doesn't exist, it will then tell you if file.isFile(). That is, because the file doesn't exist then your program only prints out False.
How can it be a file or a directory until it exists? In Linux and Windows (though Explorer itself doesn't allow you to include a .), file.txt is a valid name for both a file and a directory, so Java couldn't possibly know how you (or your user) intended to use it.

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()

What's the difference between getPath(), getAbsolutePath(), and getCanonicalPath() in Java?

What's the difference between getPath(), getAbsolutePath(), and getCanonicalPath() in Java?
And when do I use each one?
Consider these filenames:
C:\temp\file.txt - This is a path, an absolute path, and a canonical path.
.\file.txt - This is a path. It's neither an absolute path nor a canonical path.
C:\temp\myapp\bin\..\\..\file.txt - This is a path and an absolute path. It's not a canonical path.
A canonical path is always an absolute path.
Converting from a path to a canonical path makes it absolute (usually tack on the current working directory so e.g. ./file.txt becomes c:/temp/file.txt). The canonical path of a file just "purifies" the path, removing and resolving stuff like ..\ and resolving symlinks (on unixes).
Also note the following example with nio.Paths:
String canonical_path_string = "C:\\Windows\\System32\\";
String absolute_path_string = "C:\\Windows\\System32\\drivers\\..\\";
System.out.println(Paths.get(canonical_path_string).getParent());
System.out.println(Paths.get(absolute_path_string).getParent());
While both paths refer to the same location, the output will be quite different:
C:\Windows
C:\Windows\System32\drivers
The best way I have found to get a feel for things like this is to try them out:
import java.io.File;
public class PathTesting {
public static void main(String [] args) {
File f = new File("test/.././file.txt");
System.out.println(f.getPath());
System.out.println(f.getAbsolutePath());
try {
System.out.println(f.getCanonicalPath());
}
catch(Exception e) {}
}
}
Your output will be something like:
test\..\.\file.txt
C:\projects\sandbox\trunk\test\..\.\file.txt
C:\projects\sandbox\trunk\file.txt
So, getPath() gives you the path based on the File object, which may or may not be relative; getAbsolutePath() gives you an absolute path to the file; and getCanonicalPath() gives you the unique absolute path to the file. Notice that there are a huge number of absolute paths that point to the same file, but only one canonical path.
When to use each? Depends on what you're trying to accomplish, but if you were trying to see if two Files are pointing at the same file on disk, you could compare their canonical paths. Just one example.
In short:
getPath() gets the path string that the File object was constructed with, and it may be relative current directory.
getAbsolutePath() gets the path string after resolving it against the current directory if it's relative, resulting in a fully qualified path.
getCanonicalPath() gets the path string after resolving any relative path against current directory, and removes any relative pathing (. and ..), and any file system links to return a path which the file system considers the canonical means to reference the file system object to which it points.
Also, each of these has a File equivalent which returns the corresponding File object.
Note that IMO, Java got the implementation of an "absolute" path wrong; it really should remove any relative path elements in an absolute path. The canonical form would then remove any FS links or junctions in the path.
getPath() returns the path used to create the File object. This return value is not changed based on the location it is run (results below are for windows, separators are obviously different elsewhere)
File f1 = new File("/some/path");
String path = f1.getPath(); // will return "\some\path"
File dir = new File("/basedir");
File f2 = new File(dir, "/some/path");
path = f2.getPath(); // will return "\basedir\some\path"
File f3 = new File("./some/path");
path = f3.getPath(); // will return ".\some\path"
getAbsolutePath() will resolve the path based on the execution location or drive. So if run from c:\test:
path = f1.getAbsolutePath(); // will return "c:\some\path"
path = f2.getAbsolutePath(); // will return "c:\basedir\some\path"
path = f3.getAbsolutePath(); // will return "c:\test\.\basedir\some\path"
getCanonicalPath() is system dependent. It will resolve the unique location the path represents. So if you have any "."s in the path they will typically be removed.
As to when to use them. It depends on what you are trying to achieve. getPath() is useful for portability. getAbsolutePath() is useful to find the file system location, and getCanonicalPath() is particularly useful to check if two files are the same.
The big thing to get your head around is that the File class tries to represent a view of what Sun like to call "hierarchical pathnames" (basically a path like c:/foo.txt or /usr/muggins). This is why you create files in terms of paths. The operations you are describing are all operations upon this "pathname".
getPath() fetches the path that the File was created with (../foo.txt)
getAbsolutePath() fetches the path that the File was created with, but includes information about the current directory if the path is relative (/usr/bobstuff/../foo.txt)
getCanonicalPath() attempts to fetch a unique representation of the absolute path to the file. This eliminates indirection from ".." and "." references (/usr/foo.txt).
Note I say attempts - in forming a Canonical Path, the VM can throw an IOException. This usually occurs because it is performing some filesystem operations, any one of which could fail.
I find I rarely have need to use getCanonicalPath() but, if given a File with a filename that is in DOS 8.3 format on Windows, such as the java.io.tmpdir System property returns, then this method will return the "full" filename.

Categories