I want to know why the JVM doesn't throw any exception when it is asked to create an invalid path such "C:invalidPath".
For example :
public static void main(String[] args) {
File f = new File("C:invalidPath");
f.mkdir();
}
The previous example create a folder named "invalidPath" in the current folder. I think that this is not normal .
The path you have specified is a legal path on Microsoft Windows. It is specified as path relative to the current working directory on the volume C. On Windows, as on DOS before it, each volume has a separate working directory associated with it, and additionally there is the notion of the current working volume.
This is not the JVM's fault or responsibility.
It is up to the underlying filesystem to convert a path specification (i.e. string) into the actual logical files that the name represents. The JVM just passes through this string to the filesystem, which determines how to handle it.
So the real question is "why does NTFS [assuming that's what you're using] interpret 'C:invalidPath' as creating that file in the current directory?". And the reason is simply, that's how paths are defined for this filesystem.
From the documentation:
If a file name begins with only a disk designator but not the backslash after the colon, it is interpreted as a relative path to the current directory on the drive with the specified letter. Note that the current directory may or may not be the root directory depending on what it was set to during the most recent "change directory" operation on that disk. Examples of this format are as follows:
"C:tmp.txt" refers to a file named "tmp.txt" in the current directory on drive C.
Related
So I have a project, and this is one of the demands:
You should have a class named Project3, containing a main method.
This program reads the levels information from a file whose name is
specified as a command-line parameter (The file should also be
relative to the class-path as described here:)
All the file names specified in the levels and block definition files
should be relative to the class path. The reason we want them to be
relative to the class path is that later we will be able to read the
files from inside a jar, something we can not do with regular File
references.
To get an input stream relative to the class path (even if it's inside
a jar), use the following:
InputStream is =
ClassLoader.getSystemClassLoader().getResourceAsStream("image.png");
The idea is to keep a folder with files(definitions and images) and
then add that folder to the class path when running the JVM:
java -cp bin:resources ... If you don't add the resources folder to
you class path you wont be able to load them with the command from
above.
When run without parameters, your program should read a default level
file, and run the game accordingly. The location of the default level
file should be hard-coded in your code, and be relative to the
classpath_.
When run without parameters, your program should read a default level file, and run the game accordingly. The location of the default level file should be hard-coded in your code, and be relative to the classpath_.
The part of the code that handles the input is:
public Void run() throws IOException {
LevelReader level = new LevelReader();
List<level> chosenLevels = new ArrayList<>();
if (args.length >= 1) {
File f = new File(args[0]);
if (f.exists()) {
chosenLevels = level.makeLevel(args[0]);
}
}
if (chosenLevels.size() == 0) {
game.runLevels(defaultLevels);
} else {
game.runLevels(chosenLevels);
}
return null;
}
So my question is:
An argument should be the full path of a file which means:
D:\desktop\level3.txt
Is it possible to read a file from every location on my computer?
Because right now I can do it only if my text file is in the
project's directory (not even in the src folder).
I can't understand the rest of their demands. What does is mean "should be hard-coded in your code, and be relative to the
classpath_." and why is it related to InputStream method(?)
I'm confused all over this.
Thanks.
A classpath resource is not the same as a file.
As you have correctly stated, the full path of a file is something like D:\desktop\level3.txt.
But if ever want to distribute your application so it can run on other computers, which probably won’t have that file in that location, you have two choices:
Ask the user to tell the program where to find the file on their computer.
Bundle the file with the compiled program.
If you place a non-.class file in the same place as .class files, it’s considered a resource. Since you don’t know at runtime where your program’s class files are located,¹ you use the getResource or getResourceAsStream method, which is specifically designed to look in the classpath.
The getResource* methods have the additional benefit that they will work both when you are developing, and when the program is packaged as a .jar file. Individual entries in a .jar file are not separate files and cannot be read using the File or FileInputStream classes.
If I understand your assignment correctly, the default level file should be an application resource, and the name of that resource is what should be hard-coded in your program. Something like:
InputStream is;
if (args.length > 0) {
is = new BufferedInputStream(
new FileInputStream(args[0]));
} else {
// No argument provided, so use program's default level data.
is = ClassLoader.getSystemClassLoader().getResourceAsStream("defaultlevel.txt");
}
chosenLevels = level.makeLevel(is);
¹ You may find some pages that claim you can determine the location of a running program’s code using getProtectionDomain().getCodeSource(), but getCodeSource() may return null, depending on the JVM and ClassLoader implementation, so this is not reliable.
To answer your first question, it doesn't seem like they're asking you to read from anywhere on disk, just from within your class path. So that seems fine.
The second question, "What does is mean 'should be hard-coded in your code, and be relative to the classpath'?". You are always going to have a default level file in your project directory. Define the path to this file as a String in your program and that requirement will be satisfied. It's related to the InputStream because the stream requires a location to read in from.
I am taking the Coursera OOP in Java class. In the module 4 assignment, I run the code that the course provides in EarthquakeCityMap.java,
and I get an error as "The file "countries.geo.json" is missing or inaccessible, make sure the URL is valid or that the file has been added to your sketch and is readable.
Exception in thread "Animation Thread" java.lang.NullPointerException"
I tried to set countryFile as
"../data/countries.geo.json",
"data/countries.geo.json",
and the complete path of countries file,
but still didn't solve the problem.
//this error points to the code
private String countryFile = "countries.geo.json";
List<Feature> countries = GeoJSONReader.loadData(this, countryFile);"
//the countries file is saved in data folder.
Poject folder listing
"countries.geo.json" (unless changed in GeoJSONReader manipulates this path) will be relative to the compiled java .class files in the IntelliJ's project out folder.
If this in GeoJSONReader.loadData(this, countryFile); is a PApplet instance you can use sketchPath() to make that path relative to the folder from which the sketch runs:
List<Feature> countries = GeoJSONReader.loadData(this, this.sketchPath("data"+File.separator+countryFile));
The above snippet is based on an assumption so the syntax in your code might be slightly different, but hopefully this illustrates how you'd use sketchPath().
Additionally there's a dataPath() as well which you can test from your main PApplet in setup() as a test:
String fullJSONPath = dataPath("countries.geo.json");
println("fullJSONPath: " + fullJSONPath);//hopefully this prints the full path to the json file on your machine
println(new File(fullJSONPath).exists());//hopefully this prints true
If you specified the full path and it didn’t work, you probably forgot to escape the \ character with another backslash. The backslash character is special and needs to be doubled for windows path to be interpreted properly. For instance “c:\\users\\...”. You can also specify / instead of \ and it would work : “c:/users/...”
That said, the path resolution of a file when relative (IE not being absolute to the file system root) is relative to the working directory of the executed app. Typically, in an IDE without any special configuration, the working directory would be the root path of the project. So in order to get the relative file path resolved properly, you would have to specify the path as “data/countries.geo.json”.
You can also find out what path you are in when you run the app by doing a System.out.println(new java.io.File(“.”).getAbsolutePath()) and craft the relative path according to this folder.
Suppose I create a txt file and save it as "Untitled1". I enter eclipse and type the following:
import java.io.*;
public class Test {
public static void main(String[] args){
File f = new File("Untitled1.txt");
boolean isDeleted = f.delete();
System.out.println(isDeleted);
}
}
False was returned from the delete method indicating the file was not deleted. I understand that a file object represents the location of a file and NOT the contents of the file. But then what is actually being deleted? How do you delete a location of a file, without deleting the contents of a file itself?
I also entered the file Path for the Untitled1 file as a parameter to the File objects constructor, that did not delete the Untitled1.txt file either.
A file is identified by its path through the file system, beginning from the root node.
Representation of the path depends on the system. e.g. in windows C:\foo\bar while in linux /home/foo/bar.
So in below code, string path would be converted into abstract pathname and it would create the File instance and when you call the delete method it will try to delete the node. Basically content and path are not really different.
File f = new File("Untitled1.txt");
So, the file itself is deleted. False could be returned for a variety of reasons.
public boolean delete()
Deletes the file or directory denoted by this abstract pathname. If this pathname denotes a directory, then the directory must be empty in order to be deleted.
Note that the Files class defines the delete method to throw an IOException when a file cannot be deleted. This is useful for error reporting and to diagnose why a file cannot be deleted.
Returns:
true if and only if the file or directory is successfully deleted; false otherwise
Throws:
SecurityException - If a security manager exists and its SecurityManager.checkDelete(java.lang.String) method denies delete access to the file
Catch the SecurityException and you will probably find that you are disallowed from directly deleting the file programmatically.
First, please note that File is an old, bad class, that should not be used nowadays.
It's a lot better to use the Files class, more specifically its delete method.
As for what exactly is deleted: a file is a bunch of bytes that sits in a hard disk. The disk - or one of its partitions - is formatted into a filesystem, which is a data structure that organizes directories and files. The particular filesystem dictates how the file is broken up into pieces, how these pieces can be located or added by operations such as seek, read, write etc.
A filesystem has directories, which give you start points for the files. The file path in the hierarchy of directories tells the system where to find the file, including all its information (like pointer to its start, read/write permissions, etc.) The information in the directory that tells where the actual file contents is is sometimes called a "link" (at least in Unix file systems).
When you delete a file, the usual thing that happens is that the particular link to that file from that directory is removed. If that is the last link (the file can be linked from more than one directory, at least in some file systems), the blocks that belong to the file are also marked as free so that they can be allocated to another file.
So your File object tells the system where the file is, but the delete operation ultimately tells the system both to unlink the file from the directory (the penultimate part of the path), and if that's the last link, it also tells the system to go to the file contents and mark it as free.
This is a general description. The exact details and what happens when the content is marked as free is dependent on the particular filesystem used (e.g. ext4,reiserFS... (Linux), HFS+ (MacOS X), NTFS,FAT32... (Windows)).
I work in a Java RCP application. I am doing the following lines of code:
File file = new File(location);
String filePath = file.toURI().toString();
Desktop desktop = Desktop.getDesktop();
desktop.browse((new URL(filePath)).toURI());
where location is a String.
When the value of location is: http://www.google.com,
file.toURI()
is appending "file:/C:/eclipse%203.7.2/eclipse/" to the value and hence it becomes
file:/C:/eclipse%203.7.2/eclipse/http:/www.google.com
But when the value is: C:\Program Files,
file.toURI()
is not appending anything and returning the same value correctly.
Is there a limitation related to paths starting with http:// or something.
Does anyone have any idea on this ?
We have 2 types of file locations: relative and absolute. When the location is something like C:\User in MS Windows or /home in Linux the location is absolute and there is no need to append something at the beginning of them! But when the location is http://google.com the program append your program location at the beginning of it.
I think you need to search about URI and URL. You used them incorrectly!
java.io.File works with file paths not URLs.
So it transforms the supplied initialization parameters into the representation that is your local file system supports.
"http://" means nothing to your local file system, it's just a file name (well, wrong file name but anyway).
In the first case with "http://www.google.com" it does not see disk drive letter in the supplied value so it is considered as relative path and current working dir absolute path added as a prefix ("user.home" env var if I'm not mistaken).
In the second case, you added an absolute path "C:\Program Files". It sees disk drive letter inside and there is no sense to add anything as a prefix.
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.