Newbie user here, first time I post here so I’ll try to make it right, sorry for any mistakes in advance.
I’ve been trying to read files from within folders inside a jar and adding their paths to a string array. My jar folder structure looks like this:
.class files are located in FileIO.jar\com\yumeprojects\flowdemonstration\
images are located in FileIO.jar\com\yumeprojects\flowdemonstration\images\
when I run the program from a compiled jar file outside eclipse the result is accurate, 5 images are found and their paths are added to the array.
this is the output:
E:\Yumeprojects 2011-2012\File IO tests>java -jar "FileIO0_2.jar"
(file:/E:/Yumeprojects%202011-2012/File%20IO%20tests/FileIO0_2.jar <no signer ce
rtificates>)
com/yumeprojects/flowdemonstration/test/bakgrund01.png
com/yumeprojects/flowdemonstration/test/bakgrund02.png
com/yumeprojects/flowdemonstration/test/bakgrund03.png
com/yumeprojects/flowdemonstration/test/bakgrund04.png
com/yumeprojects/flowdemonstration/test/bakgrund05.png
Number of images: 5
When I run from within eclipse i get this:
(file:/E:/Yumeprojects%202011-2012/Project%20Mathematics/flow/bin/ <no signer certificates>)
Number of images: 0
The code looks like this and is not mine, I copied it from this site.
package com.yumeprojects.flowdemonstration;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.security.CodeSource;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class Main {
String[] fileNames;
CodeSource src = Main.class.getProtectionDomain().getCodeSource();
List<String> list = new ArrayList<String>();
public static void main(String[] args){
Main m = new Main();
m.init();
}
public void init(){
try {
read();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void read() throws IOException{
if(src != null){
URL jar = src.getLocation();
System.out.println(jar);
ZipInputStream zip = new ZipInputStream(jar.openStream());
System.out.println(zip);
System.out.println(zip.getNextEntry());
ZipEntry ze = null;
ZipEntry ze2 = null;
while((ze = zip.getNextEntry()) != null){
String entryName = ze.getName();
if(entryName.endsWith(".png") || entryName.endsWith(".PNG") ) {
list.add(entryName);
System.out.println(entryName);
}
}
}
fileNames = list.toArray(new String[list.size() ] );
System.out.println("Number of images: " + fileNames.length);
}
}
Why doesn’t this code work within eclipse? Does it need a jar file to execute within? If it does, how do I make eclipse execute it so that I can work with this code within eclipse and get the same results as I would get if I launched it from a jar outside eclipse?
Please help
//Kurten
EDIT
Since the comments wasn’t that good for parsing code i’ll parse it here instead
Syso looks like this from inside eclipse:
file:/E:/Yumeprojects%202011-2012/Project%20Mathematics/flow/bin/
java.util.zip.ZipInputStream@a62fc3
null
Number of images: 0
and outside:
E:\Yumeprojects 2011-2012\File IO tests>java -jar "FileIO0_3.jar"
file:/E:/Yumeprojects%202011-2012/File%20IO%20tests/FileIO0_3.jar
java.util.zip.ZipInputStream@649e4dc0
META-INF/MANIFEST.MF
com/yumeprojects/flowdemonstration/test/bakgrund01.png
com/yumeprojects/flowdemonstration/test/bakgrund02.png
com/yumeprojects/flowdemonstration/test/bakgrund03.png
com/yumeprojects/flowdemonstration/test/bakgrund04.png
com/yumeprojects/flowdemonstration/test/bakgrund05.png
Number of images: 5
E:\Yumeprojects 2011-2012\File IO tests>
SECOND EDIT: This is the working code! It’s not beautiful and the code structure is all to hell, but it does what it’s supposed to do. Thanks Guillaume Polet for helping me with this!
package com.yumeprojects.flowdemonstration;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.CodeSource;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class Main {
String[] fileNames;
CodeSource src = Main.class.getProtectionDomain().getCodeSource();
List<String> list = new ArrayList<String>();
URL jar;
URI jar2;
File source;
String[] images;
static boolean inIDE;
public static void main(String[] args){
if(args.length > 0){
for(int i = 0; i < args.length; i++){
if(args[i].equalsIgnoreCase("inIDE")){
inIDE = true;
}
}
}
Main m = new Main();
m.init();
}
public void init(){
try {
read();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void read() throws IOException{
if(src != null){
jar = src.getLocation();
if(inIDE){
try {
jar2 = new URI(jar.toURI().toString() + "/com/yumeprojects/flowdemonstration/test");
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(jar2);
source = new File(jar2);
images = source.list();
for(int i = 0; i < images.length; i++){
System.out.println(images[i]);
}
}else{
System.out.println(jar);
ZipInputStream zip = new ZipInputStream(jar.openStream());
System.out.println(zip);
System.out.println(zip.getNextEntry());
ZipEntry ze = null;
while((ze = zip.getNextEntry()) != null){
String entryName = ze.getName();
if(entryName.endsWith(".png") || entryName.endsWith(".PNG") ) {
list.add(entryName);
System.out.println(entryName);
}
}
fileNames = list.toArray(new String[list.size() ] );
System.out.println("Number of images: " + fileNames.length);
}
}
}
}
Well the error is as I stated in my earlier comment: within Eclipse the URL points to a file folder while executing from a packaged jar, the URL points to your jar. Creating a ZipInputStream on a folder makes no sense of course.
One way to fix your code would be to lookup how your URL ends:
If it ends with .jar, then you can keep your actual code.
If it does not, you need then a recursive method to look for your files. Convert your URL to a URI (
toURI()) and then create a File object. Then recursively scan that folder and look for your files as before.This may work for you in this situation, but I don’t think it covers all the possibilities so this is definitely the best solution.
Also, I don’t like this idea to have very different code performing the same task depending on wheter it is in development phase or production phase. You should probably try to find another approach to your problem. Some other folk may have better solutions for you.