filesystem.getPath() returns wrong path - java

This problem is driving me crazy. I have a file I would like to reach in my src/main/resources folder and I am trying to obtain the path via:
FileSystem fileSystem = FileSystems.getDefault();
Path path = fileSystem.getPath(AnalysisEngine.class.getResource("/models/10_NB_7dev_2.model").getFile());
However, I keep getting the following error:
Illegal char <:> at index 2: /C:/Users/...(the path is here)/models/10_NB_7dev_2.model
As you can see, the path returned has '/' before C:, which ruins everything. What is the reason and how could this be fixed? Is there an alternative with java.io package?
I am using Windows 8 - 64 bit OS, if it helps.

The URL returned by Class#getResource(String) contains a preceding /.
/C:/Users/...(the path is here)/models/10_NB_7dev_2.model
That's just how URLs work. Then the FileSystem tries to parse that, but it makes no sense to it that there is a : character in the mix, so it throws an exception. In other words, getPath() is trying to create a path, not a url. You cannot have a : character in a Windows (possibly linux as well) path, unless it is directly following the Drive name as the first two characters of the path string.
The solution here is not to use the path of a classpath resource. A classpath resource might not come from the filesystem directly, it might be inside a jar.

...(the path is here)/models/10_NB_7dev.model
in your code you put:
("/models/10_NB_7dev_2.model").
Are you meaning to put a _2.?

If you are not worried about using the default filesystem (e.g. if you aren't using an in-memory filesystem for testing) then you can do:
URI uri = AnalysisEngine.class.getResource("/models/10_NB_7dev_2.model").toURI();
Path path = Paths.get(uri);

Related

Error message: The file "countries.geo.json" is missing or inaccessible

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.

ClassLoader.getResource returns odd path (maybe)?

When loading an asset such as a text file from the resources folder, the most common approach is to use ClassLoader to get the path:
String path = getClass().getClassLoader().getResource("file.txt").getPath();
You can then use any of the many readers that java has to read the content of that file. But for some reason, Paths.get(path) is not happy with the path:
byte[] content = Files.readAllBytes(Paths.get(path))
-> throws java.nio.file.InvalidPathException when executed
ClassLoader.getResource(...).getPath() is returning:
/D:/Projects/myapp/build/resources/main/file.txt
Paths.get() doesn't like it. Apparently the ':' after /D is an 'Illegal char'. (Note that the path seems correct, the file is actually there)
Which one is causing the problem? Is ClassLoader.getResource() returning an invalid path or is Paths.get() acting up over nothing?
Some time later
It seems that there are multiple different formats for paths in java. The various frameworks don't appear to completely agree on what is right and what is wrong, therefore there are various discrepancies between the paths that they create and accept.
In this example, Paths.get() was in fact not expecting the leading slash in the path:
/D:/Projects/myapp/build/resources/main/vertex.vs.glsl <- EVIL
D:/Projects/myapp/build/resources/main/vertex.vs.glsl <- OK
I suppose that the question now is: How do I sanitise file paths returned by ClassLoader.getResource() for use with Paths.get() properly? Are there any other differences between their two file path formats?
"the most common approach" is not necessarily the best :)
Take care which path you mean: ClassLoader.getResource() returns a URL, which can have a path component. However, this is not necessarily a valid file-path.
Note, that there is also a method Paths.get(URI) which takes a URI as parameter
The first slash in /D:/Projects/myapp/build/resources/main/file.txt just means, that this is an absolute path: see Class.getResource
I recommend, that you simply use ClassLoader.html#getResourceAsStream when you want to read a file
Update to answer comment: "So why does Paths.get() not accept the absolute path?"
Paths.get() does accept absolute paths.
But you must pass a valid (file-)path - and in your case you pass the URL-path directly (which is not a valid file-path).
When you call: getClass().getClassLoader().getResource("file.txt") it returns a URL: file:/D:/Projects/myapp/build/resources/main/file.txt
this URL consists of the schema file:
and the valid (absolute URL)path: /D:/Projects/myapp/build/resources/main/file.txt
you try to use this URL-path directly as a file-path, which is wrong
thus the Paths.get(String,..) method throws an InvalidPathException
To convert the URL path to a valid file-path you could use the Paths.get(URI) method like so:
URL fileUrl = getClass().getClassLoader().getResource("file.txt");
Path filePath = Paths.get(fileUrl.toURI());
// now you have a valid file-path: D:/Projects/myapp/build/resources/main/file.txt
Please, have a look at the result of getClass().getClassLoader().getResource("file.txt"). It's a URL. With getPath() then you just retrieve the path part of that URL, ignoring protocol and server part. Opening the path part as a file might work under certain circumstances (in the easy cases where file syntax and URL path syntax match), but don't do it in production code.
Why? When you leave your IDE and deliver your application as JAR or WAR, the resources will reside inside a ZIP-compressed file, and there will be no file "file.txt" that you can open, there's only an entry in a JAR or WAR file.
As #TmTron pointed out, I also recommend to use ClassLoader.getResourceAsStream(). That will work in all cases.

Java nio: How to add extension to an absolute path?

This feels like it should be something straight forward, but I can seem to find an elegant solution to it without converting to File.
Given a Path
Path path = Paths.get("/a/b/foo")
How to do get the path /a/b/foo.bar? subpath will return a relative path regardless of whether the original path is relative or absolute.
I would prefer not to have to use additional libraries. But, maybe that is the only way?
To change the file name of a Path, use one of the resolveSibling() methods:
This is useful where a file name needs to be replaced with another file name.
Using this method ensures that the result Path object is for the same FileSystem as the source Path object.
So, to add extension ".bar" to a Path:
path = path.resolveSibling(path.getFileName() + ".bar");

Relative to absolute path in java

I have have a file that I want to use in my project which is in the resources package
src.res
Following what was stated in this answer, I believe that my code is valid.
File fil = new File("/res/t2.nii");
// Prints C:\\res\\t2.nii
System.out.println(fil.getAbsolutePath());
The problem is that I that file is in my projects file not there, so I get an Exception.
How am I suppose to properly convert from relative path to absolute?
Try with directory first that will provide you absolute path of directory then use file.exists() method to check for file existence.
File fil = new File("res"); // no forward slash in the beginning
System.out.println(fil.getAbsolutePath()); // Absolute path of res folder
Find more variants of File Path & Operations
Must read Oracle Java Tutorial on What Is a Path? (And Other File System Facts)
A path is either relative or absolute.
An absolute path always contains the root element and the complete directory list required to locate the file.
For example, /res/images is an absolute path.
A relative path needs to be combined with another path in order to access a file.
For example, res/images is a relative path. Without more information, a program cannot reliably locate the res/images directory in the file system.
Since you are using a Java package, you must to use a class loader if you want to load a resource. e.g.:
URL url = ClassLoader.getSystemResource("res/t2.nii");
if (url != null) {
File file = new File(url.toURI());
System.out.println(file.getAbsolutePath());
}
You can notice that ClassLoader.getSystemResource("res/t2.nii") returns URL object for reading the resource, or null if the resource could not be found. The next line convertes the given URL into an abstract pathname.
See more in Preferred way of loading resources in Java.
validate with
if (fil.exists()) { }
before and check if it really exist. if not then you can get the current path with
System.getProperty("user.dir"));
to validate that you are starting fromt he proper path.
if you really want to access the path you shouldnt use absolut pathes / since it will as explained start from the root of your Harddisk.
you can get the absolut path of the res folder by using this what my poster was writte in the previous answer:
File fil = new File("res");
System.out.println(fil.getAbsolutePath());

file.toURI() returning A Wrong value?

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.

Categories