tags:

views:

323

answers:

7

Hi there!

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 that, so please go easy on me!

Thank you very much!

A: 

your input should be the absolute or relative path of the file....

kafrlust
I wouldn't use the absolute path since that would restrict the position of the application in the file system.I've tried the relative path though and that didn't work.
Peter
+1  A: 

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.

theseion
Ok, that leaves me with this:this.getClass().getResourceAsStream("file.xml")But what do I have to do then with this? Especially with regards to the write method?
Peter
That is great news and I was completely unaware of this!Thank you very, very much!Actually I do not need to put the XML file into the JAR, the only thing I require is the file, that should be placed in the same folder as the JAR, to be readable and writable.
Peter
+1  A: 

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

ekeren
First of all thanks for you answer. This works with my IDE, but as soon as I make an application bundle, the file is no longer accessible, hence the application crashes.
Peter
+2  A: 

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.

LES2
I guess the overall problem is that the the file I try to access is not available out of my application bundle, with whatever class loading technology I use, see my comment on ekeren's post below.I really can't figure out what exactly I have to do to make this working. As I said, I'm absolutely new to this topic. :(
Peter
+1  A: 

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.

deadsven
Hi there!The file is packaged within the JAR file, which is why I don't understand why this is not working. See the comments in the first post.
Peter
+2  A: 

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();
Minus Ex
Thank you so much for your detailed explanation! I really appreciate it.Gonna give it a try!
Peter
Any update Peter? Still having issues?
Minus Ex
+1  A: 

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.

DaveG
Absolute addressing works flawless, but that would require the application to come with an installer, which I would like to avoid (OS X applications generally do not come with an installer, drag'n'drop of applications is preferred).I just can't figure why absolute addressing is working, but relative not.For example if I export the app and have set the xml files addressing to "/file.xml", I can place the bundle where ever I want, but why can't I address it relatively?Absolut
Peter
Here's a thought (by the way, your not alone with those problems. I know exactly what you're talking about....): "/file.xml" probably points to the root directory of the jar. Have you tried prepending "../" to move to the containing directory?
theseion