Opening a PDF file that is packaged in a JAR - java

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);
}

Related

Android Studio write to .properties file

I followed Where to put own properties file in an android project created with Android Studio? and I got an InputStream which reads from my .properties file successfully. However, I can't write to that .properties file, as there is no similar method to getBaseContext().getAssets().open ("app.properties") which returns an OutputStream. I have also read Java Properties File appending new values but this didn't seem to help me, my guess is my file name for the file writer is wrong but I also tried "assets\userInfo.properties" which also doesn't work.
My .properties file is in src\main\assets\userInfo.properties
Properties props = new Properties();
InputStream inputStream = null;
try{
inputStream = getBaseContext().getAssets().open("userInfo.properties");
props.load(inputStream);
props.put("name", "smith");
FileOutputStream output = new FileOutputStream("userInfo.properties"); //this line throws error
props.store(output, "This is overwrite file");
String name = props.getProperty("name");
Log.d(TAG, "onCreate: PROPERTIES TEST NAME CHANGE: " + name);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Current code throws this error:
java.io.FileNotFoundException: userInfo.properties (Read-only file system)
You can't write to the assets folder, as it is inside the APK which is read-only.
Use internal or external storage instead
You can't write to the assets folder. If you want to update your properties file, you'll have to put them some place else. If you want the initial version in the assets or raw folder, just copy it to the default files dir when the app is first used, then read from/write to it there.

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.

What folder should I store text files?

I have my classes in /src/com.example.myapp/ and I have a text mytext.txt there too.
However, when I reference static File f = new File("mytext.txt")); it does not find it, even though the file is in the same directory as the class.
What do I need to do? What directory is it actually looking in?
Assets is read-only. I need somewhere where I can read and update the text file.
Use an assets folder.
Here is an example...
Loading array from a text file in assets folder (Android)
You create the assets folder in your root project folder then place your file in it. Once it's there, you access this way:
getAssets().open("file.txt");
the getAssets method is part of your Activity / Context. Context carriers a lot of the information about your app.
If you are not in an Activity, you can pass the Context to your class and use this:
context.getAssets().open("file.txt");
If you want the file with EDIT mode, you can use Internal/External Storage
Then you can read it as:
String filePath = context.getFilesDir().getAbsolutePath(); //returns current directory.
File file = new File(filePath, fileName);
try {
BufferedReader br = new BufferedReader(new FileReader(file));
while ((line = br.readLine()) != null) {
text.append(line);
text.append('\n');
}
}
catch (IOException e) {
}
return text.toString(); //the output text from file.
You can even write to this file :
String filename = "myfile";
String string = "ur data";
FileOutputStream outputStream;
try {
outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
outputStream.write(string.getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
Hope it will help you ツ
Use the assets directory:
assets/
This is empty. You can use it to store raw asset files. Files that you save here are compiled into an .apk file as-is, and the original filename is preserved. You can navigate this directory in the same way as a typical file system using URIs and read files as a stream of bytes using the AssetManager. For example, this is a good location for textures and game data.

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.

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

Categories

Resources