JAVA getResourceAsStream() real path string interpretation of a file - java

I am using NetBeans 8.0.2 (I know there already is v8.2 but it has a lot of bugs for me so I got back to v8.0.2) and I need a string path to my .obj file for a parameter attribute like this:
api.parameter("filename", "obj/someFile.obj");
Above example worked in a previous version of my app where I had that .obj file placed in a folder called "obj" in the same directory as my .jar file, but now as I am trying to rather include it in the JAR itself with code:
api.parameter("filename", MyClass.class.getResourceAsStream("/someFile.obj").toString());
...it is not working anymore as the path string interpretation is not a path to a file, it looks more like this:
java.io.BufferedInputStream#215d7ea7
...where, of course, my code is expecting something like normal path string, I would said something in this pseudo-code manner:
api.parameter("filename", "<this.jar>/someFile.obj");
So after a fiddling a bit around StackOverflow I've found pieces of code that I thought could actually enable me to directly place that path as a string:
URL jar = MyClass.class.getProtectionDomain().getCodeSource().getLocation();
api.parameter("filename", jar + "/someFile.obj");
But surprisingly although I checked several times if the file actually really exist in my built jar file (and yes, it is there in the root) it still gives me this error:
java.io.FileNotFoundException: file:\Z:\_JAVA_\MyProject_0_018\dist\bin\myjar.jar\someFile.obj <The filename, directory name, or volume label syntax is incorrect>
And I am 100% sure the name of the file is correct, also its placement in the root of my jar file.
Or does it actually thinks that myjar.jar is a directory?
I am desperately trying to find a solution to this "path string" mess.

Your protection domain's code source location likely returns not what you'd expect it to.
You should use getResource(name) directly, like this:
URL locator = MyClass.class.getResource("someFile.obj");
api.parameter("filename", locator.toString());

Related

Java creates temp folder with shortened path and throws 'Not found' exception when trying to access files placed in it

so I did run into one very weird issue. The idea is simple: create temp dir, place some files in it and then try to access them. Now the problem is that calling File.createTempDir() or Files.createTempDirectory(prefix) creates new file inside AppData/Local/temp with shortened path, so the full path to folder looks something like C:/Users/FirstNam~1/AppData/Local/Temp/myFolder/myFile.txt instead of C:/Users/FirstName LastName/AppData/Local/Temp/myFolder.myFile.txt.
The difference is that generated path inside java contains FirstNam~1 instead of FistName SecondName. Java then throws exception File Not Found.
When I try to copy and paste shortened path into file explorer I get an error saying that file does not exist, but if I do change shortened path to full one then file opens and it works as intended.
Is there any way to fix it? Ether by forcing java to use full path names or enabling something in windows? I did Enable NTFS long paths policy, but it did not help.
This is happening when using java 8/11 and windows 10 running on VM, project is using AGP and gradle. Temp file is created inside groovy file that extends Plugin<Project>
Just when I lose hope and create a ticket, couple hours after that I find the answer. So, java has method Path.toRealPath() which solves this ~1 issue. After using this method paths no longer contain shortening and are correctly resolved.
EDIT: looks like java is doing everything correct and paths are actually valid, problem did come from library that I'm using and it's a bug with it.

Scanner cannot find (correct) file path

I'm programming in Java with IntelliJ and have been trying to use the Scanner class to read the file. Even with the correct path, I still get a "No such file or directory" error. Does anyone have any suggestions?
My working directory is /Users/kevinliu/Desktop/test
Here is a picture of how the project is set-up.
Are you trying to create a swing/console application using maven?
If yes, maven is not able to find the source. You have to add it on the pom file. See here on how to add it on pom file.
if no, do you have rights to access the address of the image file? Some times, folder are protected by the OS.
You can also use YourClassName.class.getResource("input/input1.txt") to locate file/s under the directory that your class was in.
Even with the correct path, I still get a "No such file or directory" error.
The path is NOT correct. That path says look for a directory called "src" in the root directory of your computer. That is almost certainly not where the input file lives.
If you are going to use an absolute pathname for a file within the working directory that you stated, it should look like this:
/Users/kevinliu/Desktop/test/src/input/input1.txt
(You can check what it will actually be using a file browser ... outside of Intellij.)
If you want to use a relative pathname, try this
src/input/input1.txt
Notes:
There is no leading "/" on a relative pathname. A leading "/" means it is an absolute pathname. Absolute pathnames start at the root directory.
A relative path is resolved relative to the >>current<< working directory. That will depend on where and how you run the application ...
For a production application, you would not want to refer to a file in the source tree. The end user typically won't have the source tree.
Consider making the path a command line argument or configuration setting for your application.
Consider making the file a "resource" that is part of the application's JAR file. (You would open it a different way ...)
If you ever get a "No such file or directory" message, that means that the path is not correct in some sense. You might be in the wrong place, you might not have permission on a parent directory, the file may have been removed or renamed, there may be a you, or something else. Either way, that error comes from the operating system and the OS doesn't make mistakes about these things. The mistake will be yours (or the user's).

java.nio.file.InvalidPathException with getPath

I am using this code
String path = getClass().getResource("Template.xls").getPath();
When I run it on my machine (windows), everything is good. I even did system.out.println on the get resource part and on the get path part and the results were:
file:/C:/Eclipse/Netbeans/SoftwareCom/build/classes/assets/Template.xls
/C:/Eclipse/Netbeans/SoftwareCom/build/classes/assets/Template.xls
However I am getting the following error reports from some users
java.nio.file.InvalidPathException: Illegal char <:> at index 4:
file:\C:\Software%20Com\SoftwareCom.exe!\assets\Template.xls
Iam not sure whats happening or why would it work for some and not others
Any pointers?
To answer this question properly, it would be helpful to know what you want to do with the path information. To read the file, you don't need the path.
You could just call
getClass().getResourceAsStream("Template.xls")
If you really want to know the path, you should call
URL url = getClass().getResource("Template.xls");
Path dest = Paths.get(url.toURI());
This might cause problems as you seem to pack your java files in a windows executable. See Error in URL.getFile()
Edit for your comment:
As I wrote above, you don't need the path of the source to copy. You can use
getClass().getResourceAsStream("Template.xls")
to get the content of the file and write the content to whereever you want to write it. The reason for failing is that the file in your second example is contained within an executable file:
file:\C:\Software%20Com\SoftwareCom.exe
as can be seen from the path:
file:\C:\Software%20Com\SoftwareCom.exe!\assets\Template.xls
The exclamation mark indicates that the resource is within that file.
It works within Netbeans because there the resource is not packed in a jar, but rather is a separate file on the filesystem.
You should try to run the exe-version on your machine. It will most likely fail as well. If you want more information or help, please provide the complete code.
I faced this same issue and go around it by using the good ol' File API
URL url = MyClass.class.getClassLoader().getResource("myScript.sh");
Path scriptPath = new File(url.getPath()).toPath();
And it worked!

Why my Jar doesn't run unless I extract files?

Every time I run the exported .jar file, that contains a JFrame with an image as its icon, the file doesn't run, unless I extract the file. In the compiler it is running. I dont want to make a launcher that saves both, the resources package and the jar file, in a directory.
"Why my Jar doesn't run unless I extract files?"
This seems to be the behavior of using File to your resources. Take for example
File file = new File("resources/image.png");
Image image = ImagIO.read(file);
And you project structure (Note the resources should actually be in the src, so that it builds into the jar automatically - unless you configure it differently. But for the sake of this argument, let's say you do confgigure it where resources is built to the jar)
C:\
Project
resources\image.png
Some examination:
Run from IDE - WORKS! Why? Using File looks for files on the file system. Using a relative path, the search will begin from the "working directory", which in the case of the IDE in generally the project root. So "resources/image.png" is a valid path, relative to ProjectRoot
Build jar, say it ends up in a dist dir in the project. This is what it looks like
ProjectRoot
dist
ProjectRoot.jar
Now for the sake of this argument (and is actually the correct way), let's try and print the URL of the resource in out program, so that when you run the jar, it prints out the URL of the file
URL url = Test.class.getResource("/resources/image.png");
System.out.println(url.toString());
When we run the jar C:\ProjectRoot\dist> java -jar ProjectRoot.jar We will see the print out C:\ProjectRoot\dist\ProjectRoot.jar!\resources\image.png. You can obviously see even though the current working directory is the location of the jar, the paths no longer match, with the added jar ProjectRoot.jar! location.
So why does it work when we extract it. Well when you extract it, then the path is correct
C:\ProjectRoot
dist
resources/image.png // from extracted jar
ProjectRoot.jar
When you run from the C:\ProjectRoot\dist >, the resource dir is where is should be.
Ok enough with the explanation.
For this reason, when you want to read embedded resources, they should be read from an URL as Andrew Thompson mentioned. This url should be relative to the class calling it, or the class loader. Here are a couple different ways:
As shown already
URL url = getClass().getResource("/resources/image.png");
Notice the /. This will bring us to the root of the classpath, where the resources dir will be. URL can be passed to many constructors, like ImageIcon(URL) or `ImageI.read(URL)
You can use:
InputStream is = getClass().getResourceAsStream("/resources/image.png");
Which will use an URL under the hood. You can use InputStream with many constructors also.
There's also ways to use the class loader, which will start at the root, so you don't need the /
URL url = getClass().getClassLoader().getResource("resources/image.png");
So there are a few ways you can go about it. But in general, reading File with hard coded string paths is never a good idea, when using embedded resources. It's possible to obtain the path dynamically so you can use File, but you will still need to use one of the aforementioned techniques, which unless you really need a File would be pointless, as you can do what you need with the InputStream or URL
To make a long story short
This would work
ProjectRoot
src\resources\image.png
URL url = getClass().getResource("/resources/image.png");
Image image = ImageIO.read(url);

Issues using getResource() with txt file (Java)

I have a setup in which I make use of a txt file (both reading and writing to it) in my program. At present I have it setup such that I use the local filepath on my machine, however I need to package it up into an executable JAR. To do this I've tried switching the filepath string over to the following:
String filepath = MyClass.class.getResource("/resources/textfile.txt");
However, when I run this I get a bunch of errors. After googling the method I found the similar method getResourceAsStream which I have also tried. This seems to return an InputStream object, however I need the filepath as a string ideally. Is this possible? If not what are my options?
Additional Info:
Here are the error messages I receive when trying to read & write to the txt file:
java.io.FileNotFoundException:/Users/Fred/Documents/Eclipse%20Projects/RandomProject/bin/resources/textfile.txt (No such file or directory)
Well the code you've given won't compile, because Class.getResource returns a URL, not a String. You can't treat the resource as "just another file" - because it's not.
You should basically change whatever needs to read the file to accept an InputStream instead of a filename, and then pass in the result of calling getResourceAsStream().
The method returns URL, not String. It's signature is public URL getResource(String name)
You might want to do:
String filepath = MyClass.class.getResource("/resources/textfile.txt").getPath();
I have a setup in which I make use of a txt file (both reading and writing to it) in my program.
For read only, the resource can be in a Jar on the application class-path. It is very rare (in production) for resources on the application class-path to be writable. This text file will most probably need to be put in a reproducible path (e.g. a sub-directory of user.home - where the sub-dir is based on the package name) and used as a File from that path.
Or to put that a different way. I think you are pursuing the wrong path, to achieve the goal.
If you expect to directly write to a text file inside a JAR, my friend then you are wrong all the way! Please post some more code for us to understand what is it exactly you want to achieve and how you think it could be done.

Categories

Resources