Skip to content

Instantly share code, notes, and snippets.

@trung
Last active January 2, 2024 14:33
Show Gist options
  • Save trung/2cd90faab7f75b3bcbaa to your computer and use it in GitHub Desktop.
Save trung/2cd90faab7f75b3bcbaa to your computer and use it in GitHub Desktop.
Reading files from Jar file recursively
package xyz.com;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Reading files from jar file URL, taking care of nested jar
* <ul>
* <li>jar:file:/C:/Temp/single.jar!/foo</li>
* <li>jar:file:/C:/Temp/outer.jar!/lib/inner.jar!/foo</li>
* </ul>
* @author Trung
*/
public class JarReader {
private static final Logger logger =
LoggerFactory.getLogger(JarReader.class);
public static void read(URL jarUrl, InputStreamCallback callback) throws IOException {
if (!"jar".equals(jarUrl.getProtocol())) {
throw new IllegalArgumentException("Jar protocol is expected but get " + jarUrl.getProtocol());
}
if (callback == null) {
throw new IllegalArgumentException("Callback must not be null");
}
String jarPath = jarUrl.getPath().substring(5);
String[] paths = jarPath.split("!");
FileInputStream jarFileInputStream = new FileInputStream(paths[0]);
readStream(jarFileInputStream, paths[0], 1, paths, callback);
}
private static void readStream(InputStream jarFileInputStream, String name, int i, String[] paths, InputStreamCallback callback) throws IOException {
if (i == paths.length) {
callback.onFile(name, jarFileInputStream);
return;
}
ZipInputStream jarInputStream = new ZipInputStream(jarFileInputStream);
try {
ZipEntry jarEntry = null;
while ((jarEntry = jarInputStream.getNextEntry()) != null) {
String jarEntryName = "/" + jarEntry.getName();
if (!jarEntry.isDirectory() && jarEntryName.startsWith(paths[i])) {
byte[] byteArray = copyStream(jarInputStream, jarEntry);
logger.debug("Entry {} with size {} and data size {}", jarEntryName, jarEntry.getSize(), byteArray.length);
readStream(new ByteArrayInputStream(byteArray), jarEntryName, i + 1, paths, callback);
}
}
} finally {
jarInputStream.close();
}
}
private static byte[] copyStream(InputStream inputStream) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[4 * 1024];
int n;
while ((n = inputStream.read(buffer)) > -1) {
baos.write(buffer, 0, n);
}
baos.close();
return baos.toByteArray();
}
public static interface InputStreamCallback {
void onFile(String name, InputStream is) throws IOException;
}
}
@toschneck
Copy link

toschneck commented Apr 18, 2017

thx for this, I really search since a long time for that 😃 👍

@simonjhy
Copy link

thx for this

@rtenhove
Copy link

copyStream can be simplified:

        private static byte[] copyStream(InputStream inputStream) throws IOException {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[4 * 1024];
            int n;

            while ((n = inputStream.read(buffer)) > -1) {
                baos.write(buffer, 0, n);
            }
            baos.close();

            return baos.toByteArray();
        }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment