0

I have a jar file named "san.jar" with various folders like "classes", "resources", etc., Say for e.g i have a folder structure like "resources/assets/images" under which there are various images which I do not have any information about them like name of the images or number of images under the folder as the jar file is private and I am not allowed to unzip the jar.

OBJECTIVE: I need to get all the files under the given path without iterating over the whole jar file.

Right now what I am doing is iterating through each and every entry and whenever i come across .jpg file, I perform some operation. Here for reading just the "resources/assets/images", I am iterating through the whole jarfile.

JarFile jarFile = new JarFile("san.jar");  
for(Enumeration em = jarFile.entries(); em.hasMoreElements();) {  
                String s= em.nextElement().toString();  
                if(s.contains("jpg")){  
                   //do something  
                }  
 }  

Right now what I am doing is iterating through each and every entry and whenever i come across .jpg file, I perform some operation. Here for reading just the "resources/assets/images", I am iterating through the whole jarfile.

Santhosh Raj
  • 153
  • 3
  • 13
  • 1
    is it `em.nextElement()` or `em1.nextElement()` ? – Rakesh Mar 09 '12 at 07:23
  • *"Right now what I am doing is iterating through each and every entry and whenever i come across .jpg file, I perform some operation."* Why not read them once and cache the information? – Andrew Thompson Mar 09 '12 at 07:44
  • How can i cache the information? And if you are telling me to iterate the whole jar file and cache the information, thats not my requirement as I will use this jar file only once in my application. – Santhosh Raj Mar 09 '12 at 08:02

3 Answers3

1

With Java 8 and filesystems it is pretty easy now,

Path myjar;
try (FileSystem jarfs = FileSystems.newFileSystem(myjar, null)) {
   Files.find(jarfs.getPath("resources", "assets", "images"), 
              1, 
              (path, attr) -> path.endsWith(".jpg"),
              FileVisitOption.FOLLOW_LINKS).forEach(path -> {
            //do something with the image.
    });
}

Files.find will only search the provided path up the the desired depth.

Andrew
  • 13,757
  • 13
  • 66
  • 84
0

This code works your purpose

JarFile jarFile = new JarFile("my.jar");

    for(Enumeration<JarEntry> em = jarFile.entries(); em.hasMoreElements();) {  
        String s= em.nextElement().toString();

        if(s.startsWith(("path/to/images/directory/"))){
            ZipEntry entry = jarFile.getEntry(s);

            String fileName = s.substring(s.lastIndexOf("/")+1, s.length());
            if(fileName.endsWith(".jpg")){
                InputStream inStream= jarFile.getInputStream(entry);
                OutputStream out = new FileOutputStream(fileName);
                int c;
                while ((c = inStream.read()) != -1){
                    out.write(c);
                }
                inStream.close();
                out.close();
                System.out.println(2);
            }
        }
    }  
    jarFile.close();
Rakesh
  • 4,264
  • 4
  • 32
  • 58
  • Hi Rakesh, Thanks for your reply. But dont u think, you are using the same logic as mine? you are comparing it with "startsWith()" whereas I am comparing it with "conatins()" which does the same operation. However, in both the cases, it iterates through the whole jar file. – Santhosh Raj Mar 09 '12 at 09:49
  • I don't think what you're after is possible without iterating through the whole JAR file.... – Adam Mar 09 '12 at 10:06
  • @SanthoshRaj, Yes I agree, well, you are iterating through every file in every directory and checking if the file name ends with .jpg. In my code, I am iterating files only in the required directory. So this reduces the number of iterations. – Rakesh Mar 09 '12 at 10:16
  • But not recursively through every directory. It iterates recursively only through the required directory. – Rakesh Mar 09 '12 at 11:03
  • There is no recursion as the JarFile only exposes a flat structure of entries. e.g. if you had two files foo.jpg and bar.jpg in a directory resources then the entries would be "resources/foo.jpg" and "resources/bar.jpg". Try it if you don't believe me... – Adam Mar 09 '12 at 11:05
  • @Adam, I'd be glad to see if you can make it better. No offence meant ! – Rakesh Mar 09 '12 at 11:10
0

This can be done much more concisely with a regex... It will also work when jpg files have upper case extension JPG.

JarFile jarFile = new JarFile("my.jar");

Pattern pattern = Pattern.compile("resources/assets/images/([^/]+)\\.jpg",
        Pattern.CASE_INSENSITIVE);

for (Enumeration<JarEntry> em = jarFile.entries(); em
        .hasMoreElements();) {
    JarEntry entry = em.nextElement();

    if (pattern.matcher(entry.getName()).find()) {
        BufferedImage image = ImageIO.read(jarFile
                .getInputStream(entry));
        System.out.println(image.getWidth() + " "
                + image.getHeight());

    }
}
jarFile.close();
Adam
  • 35,919
  • 9
  • 100
  • 137