read file from inside jar Not Working - java

In Java, I have tried the different techniques of reading a file inside the jar. I have gotten one to work inside another program, but not this one. The InputStream that I get from the classname.class.getClassLoader().getResourceAsStream(filenamestring); method returns null.
package mainpkg;
import java.awt.GridLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.UIManager;
public class MainClass extends JFrame{
JTextField jtf = new JTextField();
boolean isInstalling = false;
public MainClass(){
super("StringThatTitleWillBe");
}
public void initiate(){
setLookAndFeel();
setSize(550, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GridLayout bl = new GridLayout(2, 1, 10, 10);
setLayout(bl);
JButton b = new JButton("Install");
b.addMouseListener(new MouseListener(){
#Override
public void mouseClicked(MouseEvent arg0) {
if(!isInstalling){
isInstalling = true;
install();
}
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent arg0) {
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
});
add(b);
jtf.setEditable(false);
add(jtf);
//show
setVisible(true);
}
private void setLookAndFeel() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception exc) {
System.out.print("failed to load look and feel");
}
}
public static void main(String[] args){
MainClass m = new MainClass();
m.initiate();
}
public void install() {
String files = "name of jarfile inside the jar to be read";
InputStream stream = MainClass.class.getClassLoader().getResourceAsStream(files);
File f = new File(files);
if(stream == null)
System.out.println("stream is null");
try {
int val = stream.read();
BufferedWriter br = new BufferedWriter(new FileWriter(f));
while(val != -1){
br.write(val);
val = stream.read();
}
stream.close();
br.close();
} catch (IOException e) {
e.printStackTrace();
}
isInstalling = false;
}
}
It Prints "stream is null" and gives an error on the line: stream.read();
I know that means that the file is not being converted to an InputStream properly.
Have I made a stupid mistake??? please help. Thanks in advance
Edit: the file that I want to copy in the same directory as the jar is directly inside the jar. It is not in a package or any such additional directory.

If a getResourceAsStream(String) returns null, that means that the class loader can't find a resource with the name you gave it. Either it is plain wrong, or maybe you have used a relative name and the resource isn't in the "/" directory in the JAR.
For details, read the javadoc for ClassLoader.getResourceAsStream, paying careful attention to:
the value returned, and
the handling of relative pathnames (follow the getResource link!!).
If you want to load a resource using a relative name that is resolved relative the classes package, you should write this:
MainClass.class.getResourceAsStream(files);
The Class.getResource... methods resolve relative names relative to the class. So the above would resolve "foo.txt" to "/mainpkg/foo.txt" ... where your version would resolve it to "/foo.txt".

I know that means that the file is not being converted to an InputStream properly
No it doesn't. It means that the resource named was not found. Check the Javadoc.
Then check the resource name, which you have helpfully omitted from your post, against a listing of the JAR.
If 'stream' is null you have no business continuing on with trying to read it and getting an NPE. This is just poor programming.
Also, a resource inside a JAR file is not a File, and constructing a File with its name is a meaningless activity.

Related

Message console on JFrame does not work by double click on jar

So I created a message console. And used append to display messages and it works perfectly by running java -jar JavaProgram, however when I double click on it the application runs and I see the JFrame but nothing is displayed. The text that I did append is not present.
By the way, double clicking it on windows does display the message output but on my linux system nothing is displayed.
I'm running the same version of java on each machine.
Code Below:
package pdfCounter;
import java.io.*;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.Iterator;
import org.apache.commons.io.FileUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class App {
public static JTextArea textComponent;
public static int count;
public static void main(String args[]) {
try {
JFrame somePanel = new JFrame();
somePanel.add(new JLabel(" Message Console"), BorderLayout.NORTH);
textComponent = new JTextArea(5, 10);
somePanel.setVisible(true);
somePanel.setSize(900, 300);
somePanel.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
somePanel.add(new JScrollPane(textComponent));
pdfCounter.MessageConsole mc = new pdfCounter.MessageConsole(textComponent);
mc.redirectOut(null, System.out);
mc.redirectErr(Color.RED, null);
Path currentRelativePath = Paths.get("");
String s = currentRelativePath.toAbsolutePath().toString();
File root = new File(s);
count = 0;
boolean recursive = true;
Collection files = FileUtils.listFiles(root, null, recursive);
for (Iterator iterator = files.iterator(); iterator.hasNext(); ) {
try {
File file = (File) iterator.next();
if (file.getName().endsWith(".pdf")) {
String absoluteFile = file.getAbsolutePath();
append(absoluteFile);
PDDocument doc = PDDocument.load(new File(file.getAbsolutePath()));
count = doc.getNumberOfPages() + count;
doc.close();
}
} catch (Exception e) {
continue;
}
}
}
catch(Exception e) {
e.printStackTrace();
}
try (PrintStream out = new PrintStream(new FileOutputStream("NumberOfPages.txt"))) {
out.print(count);
}
catch (Exception e) {
e.printStackTrace();
}
}
public static void append(String absolutePath) {
textComponent.append(absolutePath + "\n");
}
}
when it gets to the `append(absoluteFile); part thats where the problem lies as it only appends on windows not linux.
UPDATE: I figured that opening it from a different file manager with double click, makes it work. With Nautilus is does not open, even when i choose to run it with java 8 or 9. Opening it with thunar(Different file manager) makes it work no problem with double clicking it. Both are set to run with java 9. I think it has something to do with folder permissions because if i run nautilus as root user, it works when double clicking.

Java problems with accessing resource files when application is used as library

I have two Java applications. One application will contain resource files and will be used as library to other Java application.
First app com.test.resourceusing.MainClass.java which contains res/base.xml resource file.
package com.test.resourceusing;
import java.io.BufferedInputStream;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Scanner;
public class MainClass {
public MainClass() {
super();
}
public static void main(String[] args) {
MainClass main = new MainClass();
try {
main.start();
} catch (MalformedURLException e) {
}
}
public void start() throws MalformedURLException {
URL url = getClass().getResource("res/base.xml");
System.out.println(url.getPath());
System.out.println(url.getFile());
File f = new File(url.getFile());
if (f.exists()) {
System.out.println("File exist!");
BufferedInputStream result = (BufferedInputStream)
getClass().getResourceAsStream("res/base.xml");
Scanner scn = new Scanner(result);
while(scn.hasNext()){
System.out.println(scn.next());
}
} else {
System.out.println("Not working! :(");
}
}
}
Result is:
/C:/Work/Projects/ResourceUsing/classes/com/test/resourceusing/res/base.xml
/C:/Work/Projects/ResourceUsing/classes/com/test/resourceusing/res/base.xml
File exist!
<?xml
version='1.0'
encoding='utf-8'?>
<schema>
</schema>
Then I create .jar file which contains all resource files and try to use it as library in other application.
Second app:
resourcetest.MainClassTest.java
package resourcetest;
import com.test.resourceusing.MainClass;
import java.net.MalformedURLException;
public class MainClassTest {
public MainClassTest() {
super();
}
public static void main(String[] args) {
MainClass main = new MainClass();
try {
main.start();
} catch (MalformedURLException e) {
}
}
}
Result is:
file:/C:/Work/Projects/ResourceUsing/deploy/archive1.jar!/com/test/resourceusing/res/base.xml
file:/C:/Work/Projects/ResourceUsing/deploy/archive1.jar!/com/test/resourceusing/res/base.xml
Not working! :(
I don't understand why it's not working, is there problems in my code? Or this solution is not possible in Java?
Do you see the difference in the location of those files?
/C:/Work/Projects/ResourceUsing/classes/com/test/resourceusing/res/base.xml
file:/C:/Work/Projects/ResourceUsing/deploy/archive1.jar!/com/test/resourceusing/res/base.xml
You cannot access a resource that is located in a JAR file with the File API.
Your code is already on the way. A simple edit should work:
public void start() throws IOException {
URL url = getClass().getResource("res/base.xml");
if (url != null) {
System.out.println(url.getPath());
System.out.println(url.getFile());
System.out.println("File exist!");
try(InputStream result = url.openStream()) {
try(Scanner scn = new Scanner(result)) {
while(scn.hasNext()) {
System.out.println(scn.next());
}
}
}
} else {
System.out.println("Not working! :(");
}
}
After deeper searching looks like I found a reason - https://stackoverflow.com/a/10605316/1117515.
In this case I need to use getResourceAsStream().

Reading from text file to load images from resource folder

I wanted to make a way so that I can load all the Images in my source folder without having to code each line for each image, but I keep getting an error and have tried different ways to do this and I still can't figure it out. Is it just impossible?
Here is how it works: I save all the images I am going to need on a text file (in this case startUp.txt), then I store the lines in the text file in a linked-list(String) then I use a loop to get the images and store those in a linked-list(Image) so that I don't need to write code for every single Image to load.
Here is my code:
package com.game.task;
import java.awt.Image;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.LinkedList;
import java.util.Scanner;
import javax.swing.ImageIcon;
public class imagesTest {
public LinkedList<Image> storeImages = new LinkedList<Image>();
private LinkedList<String> storeStrings = new LinkedList<String>();
public imagesTest() {
load();
readimage();
}
public void readimage() {
for(int index = 0; index < storeStrings.size(); index++){
Image temp = new ImageIcon(this.getClass().getClassLoader().getResource("/res/"+storeStrings.get(index))).getImage();
storeImages.add(temp);
}
}
private void load() {
File file = new File("Data/startUp.txt");
try {
Scanner read = new Scanner(file);
while (read.hasNextLine()) {
storeStrings.add(read.nextLine());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public static void main(String[] arsg) {
imagesTest t = new imagesTest();
}
}
Exception:
Exception in thread "main" java.lang.NullPointerException
at javax.swing.ImageIcon.<init>(ImageIcon.java:217)
at com.game.task.imagesTest.readimage(imagesTest.java:24)
at com.game.task.imagesTest.load(imagesTest.java:41)
at com.game.task.imagesTest.<init>(imagesTest.java:17)
at com.game.task.imagesTest.main(imagesTest.java:45)
I found a way to loop through the resource folder and it was not that hard.
All i had to do use make a method and keep calling it in a loop here is the code
package com.game.task;
import java.awt.Image;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.LinkedList;
import java.util.Scanner;
import javax.swing.ImageIcon;
public class imagesTest {
public LinkedList<Image> storeImages = new LinkedList<Image>();
private LinkedList<String> storeStrings = new LinkedList<String>();
public imagesTest() {
load();
start();
}
public void readimage(String f) {
Image temp = new ImageIcon(this.getClass().getResource("/res/"+f)).getImage();//looks for it
storeImages.add(temp);//put it in a linked-List(Image)
}
public void start(){
for(int index = 0; index < storeStrings.size(); index++){
readimage(storeStrings.get(index));//calling the methode to look in resource folder
}
}
//reads the text file and puts the out put in a linked-list(String)
private void load() {
File file = new File("Data/startUp.txt");
try {
Scanner read = new Scanner(file);
while (read.hasNextLine()) {
storeStrings.add(read.nextLine());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public static void main(String[] arsg) {
imagesTest t = new imagesTest();
}
}

Cannot Find Image

I'm having a problem where I can't find images through Java. My friend and I are working on a project and we've done the exact same things. I've changed the paths to the location of the images and even dragged/dropped the images into Eclipse. However, I've had no luck. Here's my code:
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Toolkit;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Map;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class MapArray {
static JPanel[][] tiles = new JPanel[30][29];
static String[][] images = new String[30][30];
final static int SIZE = 30;
static int place=0;
public MapArray(){
}
protected static ImageIcon createImageIcon(String path) {
java.net.URL imgURL = Map.class.getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL);
} else {
System.err.println("Couldn't find file: " + path);
return null;
}
}
public static void setMap(){
try {
String a = getFileContents("C:\\Users\\*****\\workspace\\Pokemon\\src\\map1.txt");
for(int x=0; x<29; x++){
for(int y=0; y<30; y++){
images[x][y]=a.substring(0,a.indexOf(" "));
a=a.substring(a.indexOf(" ")+1);
System.out.println(images[x][y]);
}
}
} catch (Exception e) {
System.out.println("y u no work :(");
}
}
public static String getFileContents(String fileName) throws Exception {
File theFile = new File(fileName);
byte[] bytes = new byte[(int) theFile.length()];
InputStream in = new FileInputStream(theFile);
int m = 0, n = 0;
while (m < bytes.length) {
n = in.read(bytes, m, bytes.length - m);
m += n;
}
in.close();
return new String(bytes);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
setMap();
JFrame frame = new JFrame();
frame.setLayout(new GridLayout(30, 29, 0, 0));
for (int i = 0; i < 29; i++) {
for (int j = 0; j < 29; j++) {
tiles[i][j] = new JPanel(new GridLayout());
tiles[i][j].add(new JLabel(
createImageIcon("C:\\Users\\*****\\workspace\\Pokemon\\src\\tile"+"-"+images[i][j]+".png")));
frame.add(tiles[i][j]);
}
}
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
});
}
}
Everything I've tried with putting in the full image path doesn't work. Also, would anyone be able to help with relative paths? My friend and I will be sharing code between multiple computers so relative paths that aren't dedicated on where our workspace is located would be great. Thanks!
// get resource of *your* class, instead of Java's Map.class
MapArray.class.getResource(path);
...
String a = getFileContents("map1.txt"); // local path, not absolute
and put the file to your src folder, next to the MapArray.java file.
src/
|-- MapArray.java
|-- ...
`-- map1.txt
map1.txt will be moved into bin directory, next to .class file (bin/ is hidden in Eclipse by default, but that's where the classpath is set). Later you'll also want to make sure that the resource file is packaged into .jar.
would anyone be able to help with relative paths?
String a = getFileContents("./src/map1.txt");
Instead of posting a a whole bunch of code and not specifying the error message you get in your question, you could start with a simple code snippet (I neglect imports, ... since I am too lazy to fire up my IDE)
public static void main( String[] args ){
File file = new File( "C:...");//with the path you use in your code
System.out.println( file.exists() );
}
This is about what you need to discover/debug your problem. Then you can start on converting it to a relative path.
If the resources are inherently part of the app. (an embedded application resource) and not for write, they should be added to a Jar on the application's run-time class-path and accessed via URL obtained from Class.getResource(). It would work something like:
URL urlToMap1 = this.getClass().getResource("/src/map1.txt");
You'd need to check the exact path in the Jar that resource ends up at, and reference it from the root of the Jar (/) then the path within the Jar (src/map1.txt).

Trying to edit a property file in jar from a ear file. Best way to do it?

I am thinking using truezip API in Java to manipulate with ear file by
extract ear into tmp directory,
then search through jars in tmp,
if found properties in jar,
then extract it into tmp,
modify that property
then pack it back into jar,
then pack jar back into ear.
OR is there a better way in using shell script?
Please advise.
Thanks
Using TrueZIP 7, you could use something like this:
public static void main(String args[]) throws IOException {
// Remember to add the following dependencies to the class path:
// Compile time artifactId(s): truezip-file
// Run time artifactId(s): truezip-kernel, truezip-driver-file, truezip-driver-zip
TFile.setDefaultArchiveDetector(new TDefaultArchiveDetector("ear|jar|war"));
search(new TFile(args[0])); // e.g. "my.ear"
TFile.umount(); // commit changes
}
private void search(TFile entry) throws IOException {
if (entry.isDirectory()) {
for (TFile member : dir.listFiles())
search(member);
} else if (entry.isFile()) {
if (entry.getName().endsWith(".properties");
update(entry);
} // else is special file or non-existent
}
private void update(TFile file) throws IOException {
Properties properties = new Properties();
InputStream in = new TFileInputStream(file);
try {
properties.load(in);
} finally {
in.close();
}
// [your updates here]
OutputStream out = new TFileOutputStream(file);
try {
properties.store(out, "updated");
} finally {
out.close();
}
}
I used the answer from #Christian Schlichtherle to get me started on what I was trying to accomplish, but the usage of True Zip has changed quite a bit. I thought I'd post what I needed to do here to hopefully help someone.
You need to create a class that extends TApplication. In my case I'm making it abstract so I can reuse the setup code in my implementing logic classes.
Application.java:
import de.schlichtherle.truezip.file.TApplication;
import de.schlichtherle.truezip.file.TArchiveDetector;
import de.schlichtherle.truezip.file.TConfig;
import de.schlichtherle.truezip.fs.archive.zip.JarDriver;
import de.schlichtherle.truezip.fs.archive.zip.ZipDriver;
import de.schlichtherle.truezip.socket.sl.IOPoolLocator;
/**
* An abstract class which configures the TrueZIP Path module.
*/
abstract class Application<E extends Exception> extends TApplication<E> {
/**
* Runs the setup phase.
* <p>
* This method is {#link #run run} only once at the start of the life
* cycle.
*/
#Override
protected void setup() {
TConfig.get().setArchiveDetector(
new TArchiveDetector(
TArchiveDetector.NULL,
new Object[][] {
{ "zip", new ZipDriver(IOPoolLocator.SINGLETON)},
{ "ear|jar|war", new JarDriver(IOPoolLocator.SINGLETON)},
}));
}
}
Then you just extend the abstract class and implement the "work" method as shown.
ChangeProperty.java:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties;
import java.util.ServiceConfigurationError;
import de.schlichtherle.truezip.file.TFile;
import de.schlichtherle.truezip.file.TFileInputStream;
import de.schlichtherle.truezip.file.TFileOutputStream;
public class ChangeProperty extends Application<IOException> {
public static void main(String args[]) throws IOException {
try {
System.exit(new ChangeProperty().run(args));
} catch (ServiceConfigurationError e) {
// Ignore this error because what we wanted to accomplish has been done.
}
}
private void search(TFile entry) throws IOException {
System.out.println("Scanning: " + entry);
if (entry.isDirectory()) {
for (TFile member : entry.listFiles())
search(member);
} else if (entry.isFile()) {
if (entry.getName().endsWith(".properties")) {
update(entry);
}
}
}
private void update(TFile file) throws IOException {
System.out.println("Updating: " + file);
Properties properties = new Properties();
InputStream in = new TFileInputStream(file);
try {
properties.load(in);
} finally {
in.close();
}
// [your updates here]
// For example: properties.setProperty(key, newValue);
OutputStream out = new TFileOutputStream(file);
try {
properties.store(out, "updated by loggerlevelchanger");
} finally {
out.close();
}
}
#Override
protected int work(String[] args) throws IOException {
search(new TFile(args[0]));
return 0;
}
}

Categories