Read / Write XML file from Java application bundle - java

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!

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....

Related

Awesome Fonts: "pr0blem reading font data" in Java

My goal is to be able to use awesome fonts an a Java GUI. For that matter I searched and found this question.
I chose the second answer to import fontawesome-webfont.ttf with an InputStream. I tailored the code to my needs because I do not need a method for my purpose.
But when it comes to testing it, I get the error: "Problem reading font data" in the line:
Font font = Font.createFont(Font.TRUETYPE_FONT, is);
This is the problematic code:
try (InputStream is = this.getClass().getResourceAsStream("C:/Users/Prak01/Documents/EclipseWorkspace/Zeiterfassung/fontawesome-webfont.ttf")) {
try {
Font font = Font.createFont(Font.TRUETYPE_FONT, is);
font = font.deriveFont(Font.PLAIN, 24f);
TextfieldFont = new JTextField("");
TextfieldFont.setFont(font);
} catch (FontFormatException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
I believe that I did everything according to the rules. The data path is correct. Could it be possible that it is because of the...
this.getClass().getResourcesAsStream();
because I changed it from:
TestFontAwsome.class.getResourceAsStream();
but I believe that it should work with this.getClass() as well.
You have mistakenly assumed that the argument to getResourceAsStream is supposed to be a file name. It is not a file name; it’s a relative URL which is resolved against each entry in the classpath. Generally, this means it should be a path in the same .jar file.
If you want to load a Font directly from a File, don’t use getResourceAsStream. Just open it as a file:
try (InputStream is = new BufferedInputStream(
Files.newInputStream(Paths.get("C:/Users/Prak01/Documents/EclipseWorkspace/Zeiterfassung/fontawesome-webfont.ttf")))) {
Note: You don’t need two try blocks. A try-with-resources statement is allowed to have a catch block:
try (InputStream is = new BufferedInputStream(
Files.newInputStream(Paths.get("C:/Users/Prak01/Documents/EclipseWorkspace/Zeiterfassung/fontawesome-webfont.ttf")))) {
// ...
} catch (FontFormatException e1) {
// ...
}

java.io.FileNotFoundException when creating FileInputStream

Getting an error when trying to open a FileInputStream to load Map from file with .ser extension.
Constructor where I create new File and invoke method that loads map from file:
protected DriveatorImpl() {
accounts = new ConcurrentHashMap<String, Client>();
db = new File("database.ser"); // oddly this does not create a file if one does not exist
loadDB();
}
#SuppressWarnings("unchecked")
private void loadDB() {
try {
fileIn = new FileInputStream(db);
in = new ObjectInputStream(fileIn);
accounts = (Map<String, Client>) in.readObject();
in.close();
fileIn.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
I've tried to create file manually and put it in same package with class, but it does not help. What's going on?!
Thank You!
You provide a relative path for the file. That means program will look for the file relative to the working directory.
Depending on how you run the program it will be the directory you run it from (if run from Shell/Cmd) or whatever is configured in the project settings (if run from the IDE). For the latter, it depends on the IDE but usually it's the project root directory.
More info on working directory: https://en.wikipedia.org/wiki/Working_directory
More info on relative path: https://en.wikipedia.org/wiki/Path_(computing)#Absolute_and_relative_paths
Regarding creation of the file, it would create non-existing file if you were to write to it. When you read it, it expects it to exist. That means you have to create empty file (if one does not exist) before reading or simply treat exception as empty content.
The path to the file you have given might be wrong for IDE it can take relative path but from the command line, it will take the absolute path.

Unable to delete text file using delete()

I am trying to transfer the data from old textfile to new textfile. Although the code below is able to transfer successfully, it does not delete the old textfile. May I know why is this so?
private void dataTransfer(String oldFilePath, String newFilePath) {
byte[] buffer = new byte[10000];
try {
FileInputStream fileInput = new FileInputStream(oldFilePath);
BufferedInputStream bufferedInput = new BufferedInputStream(fileInput);
FileOutputStream fileOutput = new FileOutputStream(newFilePath);
BufferedOutputStream bufferedOutput = new BufferedOutputStream(fileOutput);
while(true) {
int length = fileInput.read(buffer);
if(length == -1) {
break;
} else {
bufferedOutput.write(buffer);
bufferedOutput.flush();
}
}
fileInput.close();
bufferedInput.close();
fileOutput.close();
bufferedOutput.close();
File oldFile = new File(oldFilePath);
oldFile.delete();
} catch (IOException e) {
e.printStackTrace();
System.out.println(ERROR_TRANSFER_DATA);
}
}
Update the JRE and JDK, make sure you have the rights on the file. Try with a file created by you.
Also, add a catch block for SecurityException
For deleting a file it should work fine but for deleting a directory you have to make sure that Directory is Empty.
You can use the following code block. It works, though don't know. Even without setWritable, it works,
oldFile.setWritable(true);
if(!oldFile.delete()){
System.out.println("de;eted");
}
According to Oracle's docs, the delete method does not guarantee that it will delete the file.
http://docs.oracle.com/javase/7/docs/api/java/io/File.html#delete()
Deleting a file will fail if:
file does not exist
there is a lock on that file it might be opened by another process
file does not exist on the disk
you don't have enough permissions to delete that file (in this case a SecurityException is thrown)
I agree with #panagdu that you might not have sufficient rights to delete the file.
Just as a fluke try closing bufferedStream before fileInputStream
like
bufferedInput.close();
fileInput.close();
bufferedOutput.close();
fileOutput.close();
But I don't think this will help.
Test your code for files with sufficient permission. For example Java does not allow the delete() for system files.

Opening a PDF file that is packaged in a JAR

I am trying to open a PDF file that is packaged into the jar file during runtime. The basic idea is that the user clicks the help option and then it displays a help file that is a PDF. Right now I have this in LineFit.class in the linefit package to try and open the help PDF:
try {
File test = new File(LineFit.class.getClass().getResource("/linefit/helpTest.pdf").toURI());
try {
Desktop.getDesktop().open(test);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
} catch (URISyntaxException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
It works in eclipse when I run it but if I try to export it to a runnable JAR file it does not open the PDF file and when I look into the JAR, the PDF is in the same folder as when it was in eclipse.
new File(URI) only works for file: URIs. When a classloader finds a resource in a jar, it returns a jar URI, for example jar:file:/C:/Program%20Files/test.jar!/foo/bar.
Fundamentally, the File class is for files on the filesystem. You can't use it to represent a file within a JAR or another archive. You're going to have to copy the file out of the jar and into a regular file, then create a File referencing this new file. To read the file from the jar, you could use JarURLConnection.getInputStream with the URL you have, or you could call ClassLoader.getResourceAsStream.
Try this:
Make sure the path of pdf file is relative path when you use MethodHandles.lookup().lookupClass().getClassLoader()
InputStream is = MethodHandles.lookup().lookupClass().getClassLoader().getResourceAsStream("doc/example.pdf");
BufferedReader br = new BufferedReader(new InputStreamReader(is));
while ((thisLine = br.readLine()) != null) {
System.out.println(thisLine);
}

Add docx file in resources and create executable jar

I want to add
docx files in resources folder, use those files in code written in class located at another package of same application.
And then I want to make an executable jar out of it which will be working on windows.
I read its not easy to make such jar :( and there is no fool prroof way...
I have tried searching for it on net and found I will have to create URL and then file and then use it...
however, when I use below code, I am not able to get URL itself...
URL urlOfDraftInSamePackage = CreateDraft.class.getResource("Draft_in_same_package.docx");
System.out.println("urlOfDraftInSamePackage is "+urlOfDraftInSamePackage.toString());
//This prints : urlOfDraftInSamePackage is file:/D:/aditya_workspace/SampleDraftMaker/bin/draftProcessing/Draft_in_same_package.docx
URL urlOfDraftInResourceFolder = CreateDraft.class.getResource("resouces/Draft_Apartment.docx");
System.out.println("urlOfDraftInResourceFolder is "+urlOfDraftInResourceFolder.toString());
//this gives null pointer exception
URI uri = null;
try {
uri = urlOfDraftInSamePackage.toURI();
File file = new File(uri);
System.out.println("file made");
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
below is my folder structure:
can anyone pls help me in creating such executable jar using eclipse?
Thanks In Advance!!!
Following code works for me:
public static void testResource() throws IOException {
InputStream stream = Deserializace.class.getResourceAsStream("resources/ser.log");
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
String s;
while ( (s = reader.readLine()) != null) {
System.out.println(s);
}
}
Build directory structure:
Test.class
resources/ser.log
You must ensure that your resource directory is copied to correct place.

Categories

Resources