Java, display chm file loaded from resources in jar - java

I am trying to display the chm file containing the help which is loaded from resources:
try
{
URL url = this.getClass().getResource("/resources/help.chm");
File file = new File(url.toURI());
Desktop.getDesktop().open(file); //Exception
}
catch (Exception e)
{
e.printStackTrace();
}
When the project is run from NetBeans, the help file is displayed correctly.
Unfortunately, it does not work, when the program is run from the jar file; it leads to an exception.
In my opinion, the internal structure of jar described by URI has not been recognized... Is there any better way? For example, using the BufferReader class?
BufferedReader in = new BufferedReader( new InputStreamReader(url.openStream()));
An analogous problem with the jpg file has been fixed with the BufferedImage class
BufferedImage img = null;
URL url = this.getClass().getResource("/resources/test.jpg");
if (url!= null)
{
img = ImageIO.read(url);
}
without any conversion to URI...
Thanks for your help...

A .jar file is a zip file with a different extension. An entry in a .jar file is not itself a file, and trying to create a File object from a .jar resource URL will never work. Use getResourceAsStream and copy the stream to a temporary file:
Path chmPath = Files.createTempFile(null, ".chm");
try (InputStream chmResource =
getClass().getResourceAsStream("/resources/help.chm")) {
Files.copy(chmResource, chmPath,
StandardCopyOption.REPLACE_EXISTING);
}
Desktop.getDesktop().open(chmPath.toFile());
As an alternative, depending on how simple your help content is, you could just store it as a single HTML file, and pass the resource URL to a non-editable JEditorPane. If you want to have a table of contents, an index, and searching, you might want to consider learning how to use JavaHelp.

Related

Java jar not reading files from the jar, only external folders?

When ever I make a JAR, the JAR won't read the folder inside it, only a folder in the folder the JAR is it. OK, that wasn't very descriptive. So here is a photo I edited to support.
I hope you get the idea now. So how would I fix this? I already have res and stats part of the build path in eclipse, now what?
Code I use to read the resources:
Image player;
player = new ImageIcon("res/player.png").getImage();
When using ImageIcon and passing it a String, it expects that the parameter refers to a File.
From the JavaDocs
Creates an ImageIcon from the specified file. ... The specified String
can be a file name or a file path
Files and "resources" are different things.
Instead, try using something more like...
new ImageIcon(getClass().getResource("res/player.png"));
Assuming that res/player.png resides within the jar in side the res directory.
Depending on the relationship to the class trying to load the resource and the resource's location, you may need to use
new ImageIcon(getClass().getResource("/res/player.png"));
instead...
Updated
Some recommendations, as EJP has pointed, you should be prepared for the possibility that the resource won't be found.
URL url = getClass().getResource("/res/player.png");
ImageIcon img = null;
if (url != null) {
img = new ImageIcon(url);
}
// Deal with null result...
And you should be using ImageIO.read to read images. Apart from the fact that it supports more (and can support more into the future) image formats, it loads the image before returning and throws an IOException if the image can't be read...
URL url = getClass().getResource("/res/player.png");
ImageIcon icon = null;
if (url != null) {
try {
BufferedImage img = ImageIO.read(url);
icon = new ImageIcon(img);
} catch (IOException exp) {
// handle the exception...
exp.printStackTrace();
}
}
// Deal with null result...

File is not opening in java which is inside jar file

I tried to open file form my java application. Using following code from
Open PDF file on fly from Java application
Code:
if (Desktop.isDesktopSupported()) {
try {
File myFile = new File("/path/to/file.pdf");
Desktop.getDesktop().open(myFile);
} catch (IOException ex) {
// no application registered for PDFs
}
}
When I use path like :
"C:\\Users\\kalathoki\\Documents\\NetBeansProjects\\TestJava\\src\\files\\test.pdf"
it opens. But my file is inside my package
files/test.pdf
and I used
files\\test.pdf
it shows following exception:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: The file: \files\test.pdf doesn't exist.
Why? Any Idea... I want to include my file inside my jar file that can open from my application whenever user wants.
Thanks...
getDesktop#open only allows files to be opened from the file system. One solution is to keep the PDF file locally on the file system and read from there. This eliminates extracting the file from the JAR itself so is more efficient.
Unfortunately, you cannot load a file through Desktop that is contained in the jar.
However, you are not out of options. A great workaround is to create a temporary file and then open it as detailed here.
Good luck!
Assuming test.pdf is in the package files, try this:
File myFile = new File(getClass().getResource("/files/test.pdf").toURI());
This code is working properly please use this to open pdf file within jar file
try {
// TODO add your handling code here:
String path = jTextField1.getText();
System.out.println(path);
Path tempOutput = null;
String tempFile = "myFile";
tempOutput = Files.createTempFile(tempFile, ".pdf");
tempOutput.toFile().deleteOnExit();
InputStream is = getClass().getResourceAsStream("/JCADG.pdf");
Files.copy(is,tempOutput,StandardCopyOption.REPLACE_EXISTING);
if(Desktop.isDesktopSupported())
{
Desktop dTop = Desktop.getDesktop();
if(dTop.isSupported(Desktop.Action.OPEN))
{
dTop.open(tempOutput.toFile());
}
}
} catch (IOException ex) {}

finding path from directory present in jar

I am trying to use a jar file which itself is a web application in another web project. In my jar which i have created using eclipse's export to jar functionality, I have stored a directory.To access the files the from that directory i am using
BufferdReader tempDir = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream(myDirPath),"UTF-8"));
// Then i iterate on tempDir
String line;
ArrayList<File> tempDirList = new ArrayList<File>();
int c = 0;
try {
while((line = tempDir.readLine())!= null)
{
File f = new File(line);
tempDirList.add(f);
c++;
}
} catch (IOException e)
{
e.printStackTrace();
}
Now on itrating on tempDirList when i try to read the file i need file path from which i get file but I did not get file path.
So i want to know that how i get file path?
You cannot access the files in the JAR as File objects since in the web container they might not get unpacked (so there is no file). You can only access them via streams as you did.
getClass().getResourceAsStream(myDirPath + "/file1.txt");
If you really need File objects (most of the times it's quite easy to avoid that), copy the files into temporary files which you then can access.
File tmp = File.createTemp("prefix", ".tmp");
tmp.deleteOnExit();
InputStream is = getClass().getResourceAsStream(myDirPath + "/file1.txt");
OutputStream os = new FileOutputStream(tmp);
ByteStreams.copy(is, os);
os.close();
is.close();
But as I said, using streams instead of file objects in the first place makes you more flexible.
If you really don't know all the files in the directory at compile time you might be interested in this answer to list contents.

Java Jar file: use resource errors: URI is not hierarchical

I have deployed my app to jar file. When I need to copy data from one file of resource to outside of jar file, I do this code:
URL resourceUrl = getClass().getResource("/resource/data.sav");
File src = new File(resourceUrl.toURI()); //ERROR HERE
File dst = new File(CurrentPath()+"data.sav"); //CurrentPath: path of jar file don't include jar file name
FileInputStream in = new FileInputStream(src);
FileOutputStream out = new FileOutputStream(dst);
// some excute code here
The error I have met is: URI is not hierarchical. this error I don't meet when run in IDE.
If I change above code as some help on other post on StackOverFlow:
InputStream in = Model.class.getClassLoader().getResourceAsStream("/resource/data.sav");
File dst = new File(CurrentPath() + "data.sav");
FileOutputStream out = new FileOutputStream(dst);
//....
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) { //NULL POINTER EXCEPTION
//....
}
You cannot do this
File src = new File(resourceUrl.toURI()); //ERROR HERE
it is not a file!
When you run from the ide you don't have any error, because you don't run a jar file. In the IDE classes and resources are extracted on the file system.
But you can open an InputStream in this way:
InputStream in = Model.class.getClassLoader().getResourceAsStream("/data.sav");
Remove "/resource". Generally the IDEs separates on file system classes and resources. But when the jar is created they are put all together. So the folder level "/resource" is used only for classes and resources separation.
When you get a resource from classloader you have to specify the path that the resource has inside the jar, that is the real package hierarchy.
If for some reason you really need to create a java.io.File object to point to a resource inside of a Jar file, the answer is here: https://stackoverflow.com/a/27149287/155167
File f = new File(getClass().getResource("/MyResource").toExternalForm());
Here is a solution for Eclipse RCP / Plugin developers:
Bundle bundle = Platform.getBundle("resource_from_some_plugin");
URL fileURL = bundle.getEntry("files/test.txt");
File file = null;
try {
URL resolvedFileURL = FileLocator.toFileURL(fileURL);
// We need to use the 3-arg constructor of URI in order to properly escape file system chars
URI resolvedURI = new URI(resolvedFileURL.getProtocol(), resolvedFileURL.getPath(), null);
File file = new File(resolvedURI);
} catch (URISyntaxException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
It's very important to use FileLocator.toFileURL(fileURL) rather than resolve(fileURL)
, cause when the plugin is packed into a jar this will cause Eclipse to create an unpacked version in a temporary location so that the object can be accessed using File. For instance, I guess Lars Vogel has an error in his article - http://blog.vogella.com/2010/07/06/reading-resources-from-plugin/
I got a similiar issues before, and I used the code:
new File(new URI(url.toString().replace(" ","%20")).getSchemeSpecificPart());
instead of the code :
new File(new URI(url.toURI())
to solve the problem
While I stumbled upon this problem myself I'd like to add another option (to the otherwise perfect explanation from #dash1e):
Export the plugin as a folder (not a jar) by adding:
Eclipse-BundleShape: dir
to your MANIFEST.MF.
At least when you export your RCP app with the export wizard (based on a *.product) file this gets respected and will produce a folder.
In addition to the general answers, you can get "URI is not hierarchical" from Unitils library attempting to load a dataset off a .jar file. It may happen when you keep datasets in one maven submodule, but actual tests in another.
There is even a bug UNI-197 filed.

How to read file from relative path in Java project? java.io.File cannot find the path specified

I have a project with 2 packages:
tkorg.idrs.core.searchengines
tkorg.idrs.core.searchengines
In package (2) I have a text file ListStopWords.txt, in package (1) I have a class FileLoadder. Here is code in FileLoader:
File file = new File("properties\\files\\ListStopWords.txt");
But I have this error:
The system cannot find the path specified
Can you give a solution to fix it?
If it's already in the classpath, then just obtain it from the classpath instead of from the disk file system. Don't fiddle with relative paths in java.io.File. They are dependent on the current working directory over which you have totally no control from inside the Java code.
Assuming that ListStopWords.txt is in the same package as your FileLoader class, then do:
URL url = getClass().getResource("ListStopWords.txt");
File file = new File(url.getPath());
Or if all you're ultimately after is actually an InputStream of it:
InputStream input = getClass().getResourceAsStream("ListStopWords.txt");
This is certainly preferred over creating a new File() because the url may not necessarily represent a disk file system path, but it could also represent virtual file system path (which may happen when the JAR is expanded into memory instead of into a temp folder on disk file system) or even a network path which are both not per definition digestable by File constructor.
If the file is -as the package name hints- is actually a fullworthy properties file (containing key=value lines) with just the "wrong" extension, then you could feed the InputStream immediately to the load() method.
Properties properties = new Properties();
properties.load(getClass().getResourceAsStream("ListStopWords.txt"));
Note: when you're trying to access it from inside static context, then use FileLoader.class (or whatever YourClass.class) instead of getClass() in above examples.
The relative path works in Java using the . specifier.
. means same folder as the currently running context.
.. means the parent folder of the currently running context.
So the question is how do you know the path where the Java is currently looking?
Do a small experiment
File directory = new File("./");
System.out.println(directory.getAbsolutePath());
Observe the output, you will come to know the current directory where Java is looking. From there, simply use the ./ specifier to locate your file.
For example if the output is
G:\JAVA8Ws\MyProject\content.
and your file is present in the folder "MyProject" simply use
File resourceFile = new File("../myFile.txt");
Hope this helps.
The following line can be used if we want to specify the relative path of the file.
File file = new File("./properties/files/ListStopWords.txt");
InputStream in = FileLoader.class.getResourceAsStream("<relative path from this class to the file to be read>");
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line = null;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (Exception e) {
e.printStackTrace();
}
try .\properties\files\ListStopWords.txt
I could have commented but I have less rep for that.
Samrat's answer did the job for me. It's better to see the current directory path through the following code.
File directory = new File("./");
System.out.println(directory.getAbsolutePath());
I simply used it to rectify an issue I was facing in my project. Be sure to use ./ to back to the parent directory of the current directory.
./test/conf/appProperties/keystore
While the answer provided by BalusC works for this case, it will break when the file path contains spaces because in a URL, these are being converted to %20 which is not a valid file name. If you construct the File object using a URI rather than a String, whitespaces will be handled correctly:
URL url = getClass().getResource("ListStopWords.txt");
File file = new File(url.toURI());
Assuming you want to read from resources directory in FileSystem class.
String file = "dummy.txt";
var path = Paths.get("src/com/company/fs/resources/", file);
System.out.println(path);
System.out.println(Files.readString(path));
Note: Leading . is not needed.
I wanted to parse 'command.json' inside src/main//js/Simulator.java. For that I copied json file in src folder and gave the absolute path like this :
Object obj = parser.parse(new FileReader("./src/command.json"));
For me actually the problem is the File object's class path is from <project folder path> or ./src, so use File file = new File("./src/xxx.txt"); solved my problem
For me it worked with -
String token = "";
File fileName = new File("filename.txt").getAbsoluteFile();
Scanner inFile = null;
try {
inFile = new Scanner(fileName);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while( inFile.hasNext() )
{
String temp = inFile.next( );
token = token + temp;
}
inFile.close();
System.out.println("file contents" +token);
If text file is not being read, try using a more closer absolute path (if you wish
you could use complete absolute path,) like this:
FileInputStream fin=new FileInputStream("\\Dash\\src\\RS\\Test.txt");
assume that the absolute path is:
C:\\Folder1\\Folder2\\Dash\\src\\RS\\Test.txt
String basePath = new File("myFile.txt").getAbsolutePath();
this basepath you can use as the correct path of your file
if you want to load property file from resources folder which is available inside src folder, use this
String resourceFile = "resources/db.properties";
InputStream resourceStream = ClassLoader.getSystemClassLoader().getResourceAsStream(resourceFile);
Properties p=new Properties();
p.load(resourceStream);
System.out.println(p.getProperty("db"));
db.properties files contains key and value db=sybase
If you are trying to call getClass() from Static method or static block, the you can do the following way.
You can call getClass() on the Properties object you are loading into.
public static Properties pathProperties = null;
static {
pathProperties = new Properties();
String pathPropertiesFile = "/file.xml";
// Now go for getClass() method
InputStream paths = pathProperties.getClass().getResourceAsStream(pathPropertiesFile);
}

Categories

Resources