Converting Java URL to valid File path in Linux - java

Ok I'm developing in Linux using Eclipse a program that needs to read a text file. The idea is to have the JAR and text file on the same folder. So I'm getting the text file path like this:
Client.class.getClassLoader().getResource("Client.class");
This correctly returns the path and I append the file name and get the below path:
/home/marquinio/workspace/my_project/info.txt
Problem is when I export my project into an executable JAR file. The JAR can't read the file. I double checked and everything looks fine. The only problem I see is that now the path has some "file:" appended at the beginning like this:
file:/home/marquinio/workspace/my_project/info.txt
which is probably why I'm getting a "FileNotFoundException". The JAR and text file are both in the same folder.
Anyone knows how to fix this? Why would Java behave different between Eclipse and executing JAR in command prompt?
Is there a replacement to the "...getResource(...)" provided by Java without that "file:"?
NOTE: this JAR should also be compatible in Windows environment. Still need to test it.
Thanks in advance.

The resource you are referring to is not guaranteed to be a file on the file system. Why not use ClassLoader#getResourceAsStream()? Without looking into the details, my best guess is that the different behavior you are seeing is because a different classloader is being used in each case above.

Related

My .exe file from launch4j does not work like my java file. Am I missing something?

As someone new to java and bundling programs with code, I was able to successfully get the proper output running a simple new HelloWorld java file. So I believe there are no issues with the java file in terms of compiling it to a class file or running it afterwards, and that I have all the files needed in the java kit to create an executable file. However, I am not sure if I am using launch4j properly to get the .exe, either with setting up the .jar or through the process from making a proper .xml file.
The code below shows what I get when I try to put everything into the .jar file, but I guess the output is an error because a new .jar file isn't produced unless I take out the "m" from the "cvfm" in the jar command. The code does show something about the manifest being added regardless when doing so, yet I still do not get a proper application. After getting the correct output without launch4j, I stopped recreating the .java and .class files and just focused on the .xml when recreating the .jar file achieved no difference. I have tried in launch4j leaving the environment variables blank in the JRE tab or just included the same path of the system variables that the java file worked with correctly in the command prompt, and I have also switched the check of GUI to console in the header tab. Research has also told me to look up a manifest.mf file, to which I don't think I have that precise file in the JDK, but may have found something similar in the kit (at least when looking in typical areas like the bin folder).
C:\JavaTest>jar cvfm HelloWorld.jar HelloWorld.class
java.io.IOException: invalid header field
at java.util.jar.Attributes.read(Attributes.java:406)
at java.util.jar.Manifest.read(Manifest.java:234)
at java.util.jar.Manifest.<init>(Manifest.java:81)
at java.util.jar.Manifest.<init>(Manifest.java:73)
at sun.tools.jar.Main.run(Main.java:176)
at sun.tools.jar.Main.main(Main.java:1288)
C:\JavaTest>jar cvf HelloWorld.jar HelloWorld.class
added manifest
adding: HelloWorld.class(in = 426) (out= 289)(deflated 32%)
I always get a warning about signing when testing the wrapper, but I don't think that has been an issue like an actual error. Due to the nature of the numerous combinations, it is hard to keep track of what caused the differences in issues, but it seems that now leaving the JRE tab blank except for having a min JRE version yields the error "no main manifest attribute" right from the wrapper test in launch4j. Having the very end of the system variable path included in the environment variable field does the same thing. Before trying to recreate the .jar, switching the header to console would create a .exe without errors, but either opening the application would either do nothing or put the same "no main manifest attribute" output in the command prompt. Now, I can't even use launch4j to test wrappers that have the header on console even when building them produces no errors (yet the same error happens when opening the .exe). I am just trying to get the .exe produced from launch4j to provide the same output in the command prompt that I get when typing "java HelloWorld" there.
If I am indeed creating the .jar properly and working with launch4j properly, did I just miss the unlisted step of needing some sort of manifest file to work with launch4j? If so, how would I make sure I got it properly? Would it be seen in a bin folder or completely separate from the JDK? Would I need to move it to my JavaTest folder where the java/class/jar/exe files are? Any help is truly appreciated.
The 'm' in jar cvfm stands for manifest, and implies that you will be providing a file as argument which is the manifest. The f stands for: You will specify the file name.
So, HelloWorld.jar is the argument to the f, and HelloWorld.class is the argument to the m. Your class file, obviously, isn't a valid manifest file, hence why the error occurs.
Generally, use a build tool to make jars, such as maven or gradle. You need a manifest in order to have a Main-Class attribute, and you need a Main-Class attribute to create a runnable jar, and you need a runnable jar to launch4j-ify it.
Make a file named MANIFEST.MF. Create it with a plain text editor. It should contain:
Main-Class: com.foo.thisIsAPackage.YourMainClass
and nothing else.
Then:
jar cvfm HelloWorld.jar MANIFEST.MF YourMainClass.class
note that I'm pretty sure you MUST have a package or this is not going to work.

Java isn't getting the file in the source code when compiled

Recently I have an issue with Java. I've tried some things I found on the web but they haven't worked, so I need help.
I have a Java project in Eclipse. My main class is in src/programCode/UI_Main2.java. In that .java I try to access to a file in src/files/File.file
And this is when the things fo weird.
If I use /src/files/File.file it gives me NoSuchFileException.
If I use src/files/File.file it works in Eclipse but when I compile it to a executable .jar it gives me NoSuchFileException.
If I use /files/File.file it gives me NoSuchFileException.
If I use files/File.file it gives me NoSuchFileException.
If I use files/File.file it gives meNoSuchFileException.
If I use this.getClass().getResource("/files/File.file").getPath().substring(1) (without substring it gives me Invalid character) it gives me NoSuchFileException (but it shows me the absolute path and the file exists there!)
If I use this.getClass().getResource("files/File.file").getPath() it gives me NullPointerException and the program crashes.
If I use this.getClass().getResource("src/files/File.file").getPath() it gives me NullPointerException and the program crashes.
If I use this.getClass().getResource("/src/files/File.file").getPath() it gives me NullPointerException and the program crashes.
So, I don't know what to do. src/files/File.file is the only one that works, but it doesn't when compiled to executable jar. So please, help me, I haven't found any solution yet.
Thanks!
Finding a file depends on two things:
Whether you use absolute or relative path
Where is your working directory
Under Unix-like system when you use path like /dir1/dir2/file you use absolute path, so your working directory doesn't matter, but you must have a file exactly under that path.
In your case you try to use relative path, so you shouldn't use / at the beginning.
This case is crucial to your problem:
"If I use src/files/File.file it works in Eclipse but when I compile it to a executable .jar it gives me NoSuchFileException."
By default Eclipse uses as working directory a parent directory of src (which is usually a direcotry with your project", so starting from there you indeed have a file under that path.
When you start a .jar your working directory is somewhere else. Put your .jar to parent directory of src and it should work.
Now, I suggest that you change location of the file to a directory other than src (call it Resurces or something) and provide it along with the .jar.
Also, here is an interesting discussion about working directories and .jar files:
Current working directory when running a Jar
If you want to distribute a single .jar here is a good packaging instruction:
http://www.cefns.nau.edu/~edo/Classes/CS477_WWW/Docs/pack_resources_in_jar.html
Assuming your intent is to rum your compiled program on YOUR own development computer, you need to provide the full path to the file you want. That full path would be of the form
<Eclipse workspace location>\<project name>\<file location in project>

Reading file from within JAR not working on windows

I'm trying to read from a file that is packaged up inside a JAR, along with the class that reads it. To do this, I use the following:
getClass().getClassLoader().getResourceAsStream(file)
This works fine when I create and run the JAR file on OSX, but if I create and run the JAR file on windows, the above line returns null.
Am I missing something here? If I create the JAR on OSX and run it on Windows it works fine. The problem only occurs when I create the JAR on windows.
EDIT: It's worth mentioning that there is no folder hierarchy within the JAR file. Everything is stored at one level, thus the class reading the file and the file itself are both in the same directory. Additionally, this is how I'm creating the JAR file, on both OSX and Windows:
jar -cmf manifest.mf run.jar *.class file1 file2
EDIT 2: The file I am trying to load is a java .properties file. I take it that's not what is causing the issue?
Skip the classloader part. Just getClass().getResource....
Try it this way getClass().getResourceAsStream("/file1").
When using file separators, don't hard code them!
Use java.io.File.separator instead: http://docs.oracle.com/javase/7/docs/api/java/io/File.html#separator

Putting bat file inside a jar file

I have a java class that uses a bat file to execute commands. However I developed it in Eclipse IDE. It works fine in there. But as I export it in a jar file, it fails to find the bat file that was included.(gives me an IOException)
The file structure in eclipse is as follows
:
Project1
---->src
------>com.myproj
-------->BatFileRead.java
----md.bat
----ul.bat
md.bat and ul.bat is same level as src directory. After jarring it src folder disappears.
Could someone help me with this.
Thanks
In order to execute the command, you'll have to extract the bat file afterwards. You can't run executables which are inside jar files. Basically you'll need to open the batch file entry in the jar file as an input stream, and copy the data to a FileOutputStream on disk. You won't be able to execute it until it's a proper standalone file on the file system.
If you're already trying to extract it, chances are you're using getResource or getResourceAsStream slightly incorrectly. This is easy to do, because it depends whether you're calling ClassLoader.getResourceAsStream or Class.getResourceAsStream. The first only ever uses absolute paths (implicitly) and the second can use either absolute or relative paths. For example, in your case you'd want:
BatFileRead.class.getResourceAsStream("/md.bat")
or
BatFileRead.class.getClassLoader().getResourceAsStream("md.bat")
Have you checked that the bat files are definitely ending up in the jar file? Just list the contents with
jar tvf file.jar
to see what's in there.
Well this can be very dangerous. Be sure to use gloves when dealing with the BAT. They bite and quite painfull. Also try getting jar that has a big enough opening, although the bats will fit almost through any hole.
Good luck, and don't try this at home. This is done by professionals.
Try copying file.jar to file.zip, and opening file.zip (e.g. just double clicking, or using e.g. 7-Zip). Can you find your .bat files inside? If the .bat file isn't there, you have to add the .bat file to your Eclipse project, and rebuild in Eclipse. If the .bat file is there, but you still get an IOException opening it from you .java application, then please post the code snippet triggering the IOException, and please give a full listing of file.zip (get the listing by extracting file.zip to C:\testdir, and running dir /s C:\testdir in the command line).
Please note that Jon Skeet is right that although it is possible to open any file in the .jar file as an InputStream using java.lang.Class.getResourceAsStream and java.lang.ClassLoader.getResourceAsStream (see tutorial or find them in the Java API docs), but in order to execute a .bat file inside, you have to extract the .jar file first.

Find text files in Jar

I have an app which has to read from a text file (using FileInputStream). The text file is in the directory structure relative to the class file (eg. "../textdir/text.txt"). When I run it normally (ie specifying the /bin folder containing the .class file in the cp) everything works fine. However, I somehow need to package everything into one jar and when I run the jar nothing works. The error is something like "FileNotFOund: MyJar.jar!/textdir/text.txt". I ran jar -tvf on the jarfile and the text file was indeed inside. I have read but not write access to the source code.
More than trying to solve my problem (I think there are plenty of workarounds), can someone explain to me how the whole thing work? How does the jar search for files? What if I want to read from current working directory of the command prompt instead of the directory of the .class in the jar file? Also, I recently had a similar problem with loading resources when I converted a non-jar project to a jar, how does that work?
Instead of opening the file as a FileInputStream, use getResourceAsStream which will work in both of your contexts ie. within the jar file or unpacked.

Categories

Resources