I have source folder test, in what there is package Resources.Data, that among others contains files data[0].xml, that I want to reference in webpage (it is acceptable that all files in that directory are visible). After I build the war, files are in war\WEB-INF\classes\Resources\Data. I can make a manual duplicate, to top level, but it seems a dumb thing to do.
My question is: How do I refence data[0].xml or is duplicate 'not a dumb thing to do'?
If you need the resource to be visible to the browser, then don't put it under /WEB-INF. Files in there are not visible.
It looks like you need to chance your build so that those resources are stored elsewhere, rather than copying them around.
You can read the file directly in the war.
InputStream in = MyClass.class.getResourceAsStream("/Resources/Data/data[0].xml");
You can then do whatever you need with the InputStream. This should occur inside of Java code, not in JSP.
You should consider storing this above the WEB-INF folder, though, so that it can be served directly. Duplicating the file is unnecessary.
Related
I need to store data into files inside .jar file and read it again.
I know that I can use Class.getResourceAsStream() method but it returns an InputStream that I can read from. But I look for a way to write.
I need to store data into files inside .jar file and read it again
No you don't.
Instead store the 'default' file inside the Jar. If it is changed, store the altered file in another place. One common place is a sub-directory of user.home. When checking for the file, first check the existence of an altered file on the file system, and if it does not exist, load the default file.
Note that it is generally better to describe the goal, rather than the strategy. 'Store changed file in Jar' is a strategy, whereas 'Save preferences between runs' might be the goal.
Related: What is the XY problem?
This is not really supported. In principle, you could operate on the jar file, but there's no guarantee the new contents would be correctly loaded. Let your build tools manage the jar file -- and choose something else for persistent storage managed by your program itself. Like a file.
It is unlikely that you can change a loaded jar safely. Changing it while it is being used is not a good idea.
If you want to do this, use a plain file system directory and add/remove files from it. Even this may not work as you expect.
You can manipulate any jar file using the package java.util.jar (or indeed just java.util.zip). As files inside a jar will be compressed, this isn't the most time efficient way for you to store data.
You should probably use a directory somewhere else (e.g. System.getProperty("user.home") + "/.myProgram") or see java.util.prefs.
Class.getResource() returns a URL. Theoretically, you can use this URL to create your InputStream and OutputStream. But in most cases, the generated JAR is a read-only file (or archive). So your application might trip when trying to use it.
I need to store data into files inside .jar file and read it again.
I know that I can use Class.getResourceAsStream() method but it returns an InputStream that I can read from. But I look for a way to write.
I need to store data into files inside .jar file and read it again
No you don't.
Instead store the 'default' file inside the Jar. If it is changed, store the altered file in another place. One common place is a sub-directory of user.home. When checking for the file, first check the existence of an altered file on the file system, and if it does not exist, load the default file.
Note that it is generally better to describe the goal, rather than the strategy. 'Store changed file in Jar' is a strategy, whereas 'Save preferences between runs' might be the goal.
Related: What is the XY problem?
This is not really supported. In principle, you could operate on the jar file, but there's no guarantee the new contents would be correctly loaded. Let your build tools manage the jar file -- and choose something else for persistent storage managed by your program itself. Like a file.
It is unlikely that you can change a loaded jar safely. Changing it while it is being used is not a good idea.
If you want to do this, use a plain file system directory and add/remove files from it. Even this may not work as you expect.
You can manipulate any jar file using the package java.util.jar (or indeed just java.util.zip). As files inside a jar will be compressed, this isn't the most time efficient way for you to store data.
You should probably use a directory somewhere else (e.g. System.getProperty("user.home") + "/.myProgram") or see java.util.prefs.
Class.getResource() returns a URL. Theoretically, you can use this URL to create your InputStream and OutputStream. But in most cases, the generated JAR is a read-only file (or archive). So your application might trip when trying to use it.
I need to store data into files inside .jar file and read it again.
I know that I can use Class.getResourceAsStream() method but it returns an InputStream that I can read from. But I look for a way to write.
I need to store data into files inside .jar file and read it again
No you don't.
Instead store the 'default' file inside the Jar. If it is changed, store the altered file in another place. One common place is a sub-directory of user.home. When checking for the file, first check the existence of an altered file on the file system, and if it does not exist, load the default file.
Note that it is generally better to describe the goal, rather than the strategy. 'Store changed file in Jar' is a strategy, whereas 'Save preferences between runs' might be the goal.
Related: What is the XY problem?
This is not really supported. In principle, you could operate on the jar file, but there's no guarantee the new contents would be correctly loaded. Let your build tools manage the jar file -- and choose something else for persistent storage managed by your program itself. Like a file.
It is unlikely that you can change a loaded jar safely. Changing it while it is being used is not a good idea.
If you want to do this, use a plain file system directory and add/remove files from it. Even this may not work as you expect.
You can manipulate any jar file using the package java.util.jar (or indeed just java.util.zip). As files inside a jar will be compressed, this isn't the most time efficient way for you to store data.
You should probably use a directory somewhere else (e.g. System.getProperty("user.home") + "/.myProgram") or see java.util.prefs.
Class.getResource() returns a URL. Theoretically, you can use this URL to create your InputStream and OutputStream. But in most cases, the generated JAR is a read-only file (or archive). So your application might trip when trying to use it.
I am doing a project in java and in that i need to add and modify my
text file at runtime,which is grouped in the jar.
I am using class.getResourceAsStream(filename) this method we
can read that file from class path.
i want to write into the same textfile.
What is the possible solution for this.
If i can't update the text file in jar what other solution is there?
Appreciate any help.
The easiest solution here is to not put the file in the jar. It sounds like you are putting files in your jar so that your user only needs to worry about one file that contains everything related to that program. This is an artificial constraint and just add headaches.
There is a simple solution that still allows you to distribute just the jar file. At start up, attempt to read the file from the file system. If you don't find it, use default values that are encoded in you program. Then when changes are made, you can write it to the file system.
In general, you can't update a file that you located using getResourceAsStream. It might be a file in a JAR/ZIP file ... and writing it would entail rewriting the entire JAR file. It might be a remote file served up by a Url classloader.
For your sanity (and good practice), you should not attempt to update files that you access via the classpath. If you need to, read the file out of the JAR file (or whatever), copy it into the regular file system, and then update the copy.
I'm not saying that it is impossible to do this in all cases. Indeed, in most normal cases you can do it with some effort. However, this is not supported, and there are no standard APIs for doing this.
Furthermore, attempts to update resources are liable to cause anomalies in the classloader. For example, I'd expect resources in JAR files to not update (from the perspective of the application) until the application restarted. But resources in exploded JAR files probably would update ... though new resources might not show up.
Finally, there are cases where updating a resource is impossible:
When the user doesn't have write access to the application's installation directory. This is typical for a properly administered UNIX / Linux machine.
When the JAR file is fetched from a remote server, you are likely not to be able to write the updates back.
When you are using an arbitrary custom classloader, you've got no way of knowing where the actual bytes of an updated resource should be stored, and no way of storing them.
All JAR rewriting techniques in Java look similar. Open the Jar file, read all of it's contents, and write a new Jar file containing the unmodified contents (and the modifications you whished to make). Such techniques are not advisable for a Jar file on the class path, much less a Jar file you're running from.
If you decide you must do it this way, Java World has a few articles:
Modifying Archives, Part 1
Modifying Archives, Part 2
A good solution that avoids the need to put your items into a Jar file is to read (if present) a properties file out of a hidden subdirectory in the user's home directory. The logic looks a bit like this:
if (the hidden directory named after my application doesn't exist) {
makeTheHiddenDirectory();
writeTheDefaultPropertiesFile();
}
Properties appProps = new Properties();
appProps.load(new FileInputStream(fileInHiddenDir));
...
... After the appProps have changed ...
...
appProps.store(new FileOutputStream(fileInHiddenDir), "Do not modify this file");
Look to java.util.Properties, and keep in mind that they have two different load and store formats (key = value based and XML based). Pick the one that suits you best.
If i can't update the text file in jar what other solution is there?
Store the information in any of:
Cookies
The server
Deploy the applet using 1.6.0_10+, launch it using JWS and use the PersistenceService to store the information. Here is my demo. of the PersistenceService.
Also, if your users will agree to a trusted applet (which seems overkill for this), you might write the information to a sub-directory of user.home.
I'm using the Netbeans IDE, and I'm currently using a GlassFish server.
What I want to do is write to a file.
I looked at some pages, and the code I have now (that is not working as far as I know) looks like:
File outputFile = new File(getServletContext().getRealPath("/")
+ "TheFile.txt");
FileWriter fout = new FileWriter(outputFile);
fout.write("The Content");
fout.close();
This is my project's structure:
Also where will the file get placed?
Edit:
I forgot to mention there are some other folders below the ones in the picture: Test Packages, Libraries, Test Libraries and Configuration Files. However I don't think the file would get placed there.
Edit (newest):
I found out the file is stored in the /build/web folder, but this is not appearing in Netbeans. Even after I restarted it.
As you've coded, the file will be placed in public web root. That's where getRealPath("/") will point to. To be precise, it's the folder named Web Pages as in your screenshot. As an exercise, do the following to figure the absolute path, so that you can find it by OS disk explorer.
System.out.println(file.getAbsolutePath());
I don't do Netbeans, but likely you need to refresh the folder in your IDE after the write of the file so that it appears in the listing in the IDE. Click the folder and press F5. This is at least true for Eclipse.
That said, this approach is not recommended. This won't work when the servletcontainer isn't configured to expand the WAR on disk. Even when it did, you will lose all new files and changes in existing files when the WAR is been redeployed. It should not be used as a permanent storage. Rather store it on a fixed path outside the webapp or in a database (which is preferred since you seem want to reinvent a CMS).
Note that this is in no way guaranteed to work in all web containers or through restarts and will most likely be overwritten by a redeployment.
If you want to be able to allow your user to update content, you need to store the new content somewhere and have a servlet or a JSP-page or a facelet retrieve the new content from the backing storage and send it to the browser.
See the documentation for getRealPath. It returns you the location on the disk for something specified with a URL.
I'm guessing your file is in the root of your web application on the disk within Glassfish (where the WAR file is extracted). I don't know enough about Glassfish to say where that will be.
Also, note you are using string concatenation to create the file name, so if the getRealPath call doesn't return a String with a "/" on the end, then you might be creating a file in the parent directory of your web app. Perhaps best to use a File object for the parent directory when creating the File object for the actual file. Check out the File API.
I'd recommend creating the file outside of your web app. If you redeploy your WAR file then you might delete your file, which probably isn't what you want.
Being in a servlet makes little difference to the fact that you want to output a file. Just follow the standard file APIs as a starting point. Here's a tutorial.