Read / Write XML file from Java application bundle
I've got an XML file that is parsed and written in my application. From within my IDE (Eclipse) I simply address it like this:
Reading:
private String xmlFile = "file.xml";
and then I build the document:
doc = sax.build(xmlFile);
Writing is done like this:
writer = new FileWriter("file.xml");
Runs great so far, but after bundling my application, the file is no longer accessible. What exactly do I have to do to make it accessible from within an application bundle? I'm absolutely not familiar with the classpath or whatever I need for th开发者_运维百科at, so please go easy on me!
Thank you very much!
To read the file you can create a BufferedReader as follows:
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
getClass().getResourceAsStream("file.xml")));
You can write the file as before, but keep track of where it's written to - then you can re-read the file from there if necessary.
Peter,
I've run into a similar issue, and since you're new to this, I'll start with this: When you package a file in a jar, it is compressed, and so accessing it like you have in your original code will not work, as we cannot read the files compressed in the jar. Instead, you need to ask Java to pull out this resource as a stream (as many others have helpfully pointed out) which Java does know how to supply to you.
Now, actually outputting the file from there IS a pain. Here's some code I wrote a while back to do this, which is of course from some other source I found. Fill in the exceptions as needed! =)
InputStream in = null;
in = this.getClass().getResourceAsStream("/main.cc");
File outputFile = createMainOutputFile();
OutputStream out = null;
try {
out = new FileOutputStream(outputFile);
} catch (FileNotFoundException e) {
System.out.println(outputFile + " was not found!");
e.printStackTrace();
}
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
try {
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
We actually have to output the file piece by piece, sad I know, I really wish what you were hoping to do worked! It'd make life a lot easier. The only thing that may be confusing there is the createMainOutputFile() call, so here's the code for that too...
private File createMainOutputFile() {
File directoryPath = new File(mainOutputFolder);
directoryPath.mkdirs();
File newFile = new File (mainOutputFolder + "main.cc");
try {
newFile.createNewFile();
} catch (IOException e) {
System.out.println("failed To create new file.");
e.printStackTrace();
}
return newFile;
}
Best of Luck!
Edit: Now that I notice you're actually parsing it with an XML parser, I'll point out to you that if you're using a SAX parser (at least apache's) you'll find that it will actually accept an inputStream just like it would a file:
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = null;
try {
docBuilder = docFactory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
//Here we supply the inputStream instead of the file...
doc = docBuilder.parse(inputStream);
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Node xmlRoot = doc.getFirstChild();
Imagine that you have a package named myXmlDir put your file.xml file under this package (a directory actually)
Notice that this package is packaged with you class inside the jar and can be accessed by the classLoader.
See this code that return an input stream:
return SomeClass.class.getClassLoader().getResource("myXmlDir/file.xml").openStream();
you can also, instead of openStream(), activate the getFile() function
I can't comment, so my answer is referring to LES2's answer. The trick is that your file.xml must be on the classpath if you want to use a classloader.
Usually, it will be included in the classpath if it is in your JAR file. to check if it's there, open the jar with 7zip or any other zip program. If the file is not inside the jar, you must ship it along with the jar and add it to the classpath manually when starting the app.
lets say file.xml and the jar are in the same directory. then
java -cp .:myjar.jar com.example.Main
should help.
Use the file as a property. You can than do with it whatever you want. To access it use
Class.getResourceAsStream()
or an equivalent method. Check out this link for a few hints: http://www.javaworld.com/javaworld/javaqa/2003-08/01-qa-0808-property.html?page=2
Edit:
I'm sorry to say that my suggestion isn't as good as I thought it was. I felt that I had done something as you want to once but I looked at the app and all I did was read the files.
I also did a bit of googleing and found this forum entry which is a bit old but considering the lacking progress on Sun's part I reckon it's essence is still valid: http://lists.apple.com/archives/Java-dev/2003/Feb/msg00876.html
Basically, if you want to write something, either require the user to extract the jar before launching or (my suggestion) create a directory in the same directory as the jar is in and write your file to that directory. If you really needed to, you could even build another jar with that file and all the files of the original jar, which would of course leave you with two archives.
Sorry for bringing your hopes up.
Best option to this common problem: Absolute path for the location outside the jar/war.
The the app itself can be deployed anywhere, but the host should have a common file area such as "/common/files/someApplication"
Better yet is to have a configuration to specify (during build or at runtime) which path to use. E.g. dev build would use "/dev/myprojects/someApplication"
Not as good solution: Deploy as exploded war file. Read and write is not a problem, but now you've cause a deployment dependency.
your input should be the absolute or relative path of the file....
精彩评论