Save all files from a folder in a jar - java

First:
I know, this question was asked about 100 times already.
I know, someone already could have gave the right answer.
But anyway, I have to ask this again. I didn't found a solution working for me. sorry.
I'm writing a game in java. Of course I have many packages (folders) with sounds and pictures and so on. But these folders are each of variable size. So I want to save the content of such a folder dynamically in a list.
Usually, I was making this:
File f[] = new File(getClass.getResource("/home/res/").toURI()).listFiles();
Now I can iterate though this file object and save each file. Perfect. Really?
No. When I extract this Project into a jar archive, this fails. All because a uri isn't "hierarchical" or some stuff like this. See this exception:
C:\Users\Administrator\Desktop>java -jar Homework.jar
java.lang.IllegalArgumentException: URI is not hierarchical
at java.io.File.<init>(Unknown Source)
at homework.moonface.src.Moonface.loadSounds(Moonface.java:94)
at homework.moonface.src.Moonface.<init>(Moonface.java:55)
at control.Overview.main(Overview.java:16)
Ok, I thought, so I need to get this path and add it manual into the file object. (new File("path"); But... this doesn't work. I'm getting the known error that the input wasn't written correctly, or when i try to cut of "file:" from the resource url, it breaks because in a jar its "jar:file:" and not "file:". But also if I cut of jar:file: I'm getting null.
So, please don't mark this as a duplicate, and try to explain this shortly for me. It would help thousand other, who don't understand other solutions who aren't solutions.

Try this :
URL jarResourceURL = getClass().getResource("/home/res/");
JarURLConnection jarURLConnection = (JarURLConnection) jarResourceURL.openConnection();
Enumeration<JarEntry> entries = jarURLConnection.getJarFile().entries();
while (entries.hasMoreElements()){
entries.nextElement(); // iterate over entries and do something
}
UPD: I was thinking about how spring framework's ClassPathXmlApplicationContext resolves the resources from jars. So i investigated the source code and foud that there is an utility class org.springframework.core.io.ClassPathResource which have a convenient interface (moreover there is a possibility to get the corresponding java.io.File instance using it) and can help you to solve the problem. Here is the doc :
http://docs.spring.io/spring/docs/2.5.x/api/org/springframework/core/io/ClassPathResource.html

Related

Getting a resource's path

I have been searching for a way to get a file object from a file, in the resources folder. I have read a lot of similar questions on this website but non fix my problem exactly.
Link already referred to
how-to-get-a-path-to-a-resource-in-a-java-jar-file
that got really close to answering my question:
String path = this.getClass().getClassLoader().getResource(<resourceFileName>)
.toExternalForm()
I am trying to have a resource file that I can write data into and then bring that file object to another part of my program, I know I can technically create a temp file that, I then write data into then pass it into a part of my program, the problem with this approach is that I think it can take a lot of system recourses, my program will need to create a lot of these temp files.
Is there any way, I can reuse one file in the resource folder? all I need is to get it's path (and it needs to work in a jar).I have tried this snipper of code i created for testing, i don't really know why it returns false, because in the ide it returns true.
public File getFile(String fileName) throws FileNotFoundException {
//Getting file from the resources folder
ClassLoader classLoader = getClass().getClassLoader();
URL fileUrl = classLoader.getResource(fileName);
if (fileUrl == null)
throw new FileNotFoundException("Cannot find file " + fileName);
System.out.println("before: " + fileUrl.toExternalForm());
final String result = fileUrl.toExternalForm()
.replace("jar:" , "")
.replace("file:" , "");
System.out.println("after: " + result);
return new File(result);
}
Output:
before: jar:file:/C:/Users/%myuser%/Downloads/Untitlecd.jar!/Recording.wav
after: /C:/Users/%myuser%/Downloads/Untitlecd.jar!/Recording.wav
false
i have been searching for a way to get a file object from a file in the resources folder.
This is flat out impossible. The resources folder is going to end up jarred into your distribution, and you can't edit jar files, they are read only (or at least, you should consider them so. Non-idiotic deployments will generally mark their own code files (which includes those jars) as read-only to the running process. Even if not, editing jar files is extremely heavy and not something you want to do. Even if you do, on windows, open files can't be edited/replaced like this without significant headaches).
The 'resources' folder simply isn't designed for files that are meant to be modified.
The usual strategy is to make a directory someplace (for example, the user's home dir, accessing via System.getProperty("user.home"), and then make/edit files within that dir. If you wish, you can put templates in your resources folder and use those to 'initialize' that dir hanging off the user's home dir with a skeleton version.
If you have a few ten thousand files to make, whatever process needs this needs to be adjusted to not need this. For example, by using a database (H2, perhaps, if you want to ship it with your java app and have it be as low impact as possible).

Null pointer exception on getResource

I ma new to this so I am sorry if this is a stupid question. But please I need your help. I have the following directories in ecplise: Directory Hierarchy of course with a directory containing all these files.
I am trying to use get class.getResource to access a file called "data.txt" as such:
scanObj = new Scanner(new File(this.getClass().getResource("resources/data.txt").toExternalForm()));
But I am getting a null pointer exception why is that?
Many thanks!
Any help would be much appreciated
First print value of
this.getClass().getResource("resources/data.txt")
to console. If it prints null then that's the cause of problem.
This will mostly happen if the file that you are referring to is not on the class path.
Search for posts regarding how to add files to class path in eclipse.
Because the lookup is relative to the working folder of the application. Check what that folder is (should be in the run configuration for your class in Eclipse), and construct the path relative to that location.
Alternatively, use ClassLoader.getSystemClassLoader().getResourceAsStream("data.txt") (this will net you the InputStream)

Can I make a Netbeans "empty file" part of compiled jar file?

I have 80,000 words for a crossword (among others) puzzle word pattern matcher. (User inputs "ba??" and gets, among other things, "ball, baby, bank, ..." or enters "ba*" and gets the aforementioned as well as "bat, basket, babboon...".)
I stuck the words in a Netbeans "empty file" and named it "dictionary". The file's contents are just (80,000) words, one per line. This code works like a charm to read the dictionary (code that filters is omitted):
static void showMatches(String pattern, String legal, String w) throws IOException
{
Path p = Paths.get("C:\\Users\\Dov\\Documents\\NetBeansProjects\\Masterwords\\src\\masterwords\\dictionary");
String word;
Scanner sc = new Scanner(p).useDelimiter("\r");
while(sc.hasNext()){
word = sc.next().substring(1);
gui.appendOutput(word);
}
sc.reset();
}
Is there a way to make the file (named "dictionary") become part of the compiled jar file so that I only need to "ship" one file to new, (largely helpless) users?
In another matter of curiosity...
Is it possible to make the argument to Paths.get(...) something like "masterwords/src/dictionary" to make the connection for the Scanner object to be able read it? I'm wondering if this might relate to an answer my first question. (If there's a way, I can't stumble onto it. Whatever similar string I use, I get no error, no output, no "build successful"--gotta click Run > Stop build/run.)
I'm not certain, based on your description, that my solution addresses your issue, but let me restate the problem as I understand it: You have a .jar file that relies on a dictionary resource. That resource is subject to change, and you'd like to be able to update it without having to ship out a whole new .jar containing a new dictionary.
If I'm reading you correctly, you want something like:
private File getInstallPath()
{
return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().getPath());
}
This will return the install directory of your .jar file, which is where you can put your dictionary resource so that the .jar knows where to find it. Of course, now you have a bit of a training issue, because users can move, delete or misplace your dictionary file.
Part II:
Now that you've clarified your question, let me again restate: You want to be able to read an arbitrary file included in your .jar file. Fine. You're probably trying to open the file as a file, but once the file is in your .jar, you need to treat it as a resource.
Try using:
Class myClass = Class.forName("MyClass");
ClassLoader myLoader = myclass.getClassLoader();
InputStream myStream = myLoader.getResourceAsStream(myFile);
Do you really need me to explain what "myClass," "myLoader," etc. refer to? Hint: "myClass" is whatever your class is that needs to read the file.
After leaving this thread in frustration for a couple of weeks, yesterday I found a similar question at this forum, which led me to Google "java resource files" and visit ((this URL)).
Between the two I figured out how to read a file named 'dictionary' that was created as a Netbeans "empty Java file", which was located in Source Packages ... [default package] (as shown in Netbeans Projects window) and stored as C:\Users\Dov\!Docs\Documents\NetBeansProjects\WordPatternHelp\src\dictionary:
File file = new File("src/dictionary");
...
p = file.toPath();
sc = new Scanner(p).useDelimiter("\r");
Success. Hooray.
But after compiling and executing the .jar file from a DOS command line, 'dictionary' couldn't be found. So the above only works from within Netbeans IDE.
After mostly erroneous attempts caused by the above 'success', I finally got success using #Mars' second suggestion like so:
package masterwords;
public class Masterwords
...
InputStream myStream = Class.forName("masterwords.Masterwords").
getClassLoader().getResourceAsStream("dictionary");
sc = new Scanner(myStream).useDelimiter("\r"); // NULL PTR EXCEPTION HERE
So, for whatever it might be worth, a very belated thanks (and another apology) to #Mars. It was as straightforward as he indicated. Wish I'd tried it 2 weeks ago, but I'd never seen any of the methods and didn't want to take the time to learn how they work back then with other more pressing issues at hand. So I had no idea Mars had actually written the exact code I needed (except for the string arguments). Boy, do I know how the methods work now.

FileInputStream and FileNotFound Exception

I am trying to retrieve a jrxml file in a relative path using the following java code:
String jasperFileName = "/web/WEB-INF/reports/MemberOrderListReport.jrxml";
File report = new File(jasperFileName);
FileInputStream fis = new FileInputStream(report);
However, most probably I didn't succeed in defining the relative path and get an java.io.FileNotFoundException: error during the execution.
Since I am not so experienced in Java I/O operations, I didn't solve my problem. Any helps or ideas are welcomed.
You're trying to treat the jrxml file as an object on the file-system, but that's not applicable inside a web application.
You don't know how or where your application will be deployed, so you can't point a File at it.
Instead you want to use getResourceAsStream from the ServletContext. Something like:
String resourceName = "/WEB-INF/reports/MemberOrderListReport.jrxml"
InputStream is = getServletContext().getResourceAsStream(resourceName);
is what you're after.
You should place 'MemberOrderListReport.jrxml' in classpath, such as it being included in a jar placed in web-inf\lib or as a file in web-inf\classes.
The you can read the file using the following code:
InputStream is=YourClass.class.getClassLoader().getResourceAsStream("MemberOrderListReport.jrxml");
String jasperFileName = "/web/WEB-INF/reports/MemberOrderListReport.jrxml";
Simple. You don't have a /web/WEB-INF/reports/MemoberOrderListReport.jrxml file on your computer.
You are clearly executing in a web-app environment and expecting the system to automatically resolve that in the context of the web-app container. It doesn't. That's what getRealPath() and friends are for.
check that your relative base path is that one you think is:
File f = new File("test.txt");
System.out.println(f.getAbsoluteFile());
I've seen this kind of problem many times, and the answer is always the same...
The problem is the file path isn't what you think it is. To figure it out, simply add this line after creating the File:
System.out.println(report.getAbsolutePath());
Look at the output and you immediately see what the problem is.

How to walk through Java class resources?

I know we can do something like this:
Class.class.getResourceAsStream("/com/youcompany/yourapp/module/someresource.conf")
to read the files that are packaged within our jar file.
I have googled it a lot and I am surely not using the proper terms; what I want to do is to list the available resources, something like this:
Class.class.listResources("/com/yourcompany/yourapp")
That should return a list of resources that are inside the package com.yourcompany.yourapp.*
Is that possible? Any ideas on how to do it in case it can't be done as easily as I showed?
Note: I know it is possible to know where your jar is and then open it and inspect its contents to achieve it. But, I can't do it in the environment I am working in now.
For resources in a JAR file, something like this works:
URL url = MyClass.class.getResource("MyClass.class");
String scheme = url.getProtocol();
if (!"jar".equals(scheme))
throw new IllegalArgumentException("Unsupported scheme: " + scheme);
JarURLConnection con = (JarURLConnection) url.openConnection();
JarFile archive = con.getJarFile();
/* Search for the entries you care about. */
Enumeration<JarEntry> entries = archive.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (entry.getName().startsWith("com/y/app/")) {
...
}
}
You can do the same thing with resources "exploded" on the file system, or in many other repositories, but it's not quite as easy. You need specific code for each URL scheme you want to support.
In general can't get a list of resources like this. Some classloaders may not even be able to support this - imagine a classloader which can fetch individual files from a web server, but the web server doesn't have to support listing the contents of a directory.
For a jar file you can load the contents of the jar file explicitly, of course.
(This question is similar, btw.)
The most robust mechanism for listing all resources in the classpath is currently to use this pattern with ClassGraph, because it handles the widest possible array of classpath specification mechanisms, including the new JPMS module system. (I am the author of ClassGraph.)
List<String> resourceNames;
try (ScanResult scanResult = new ClassGraph()
.whitelistPaths("com/yourcompany/yourapp")
.scan()) {
resourceNames = scanResult.getAllResources().getNames();
}
I've been looking for a way to list the contents of a jar file using the classloaders, but unfortunately this seems to be impossible. Instead what you can do is open the jar as a zip file and get the contents this way. You can use standard (here) ways to read the contents of a jar file and then use the classloader to read the contents.
I usually use
getClass().getClassLoader().getResourceAsStream(...)
but I doubt you can list the entries from the classpath, without knowing them a priori.

Categories

Resources