Чтение zip-файла в jar-файле - PullRequest
       5

Чтение zip-файла в jar-файле

7 голосов
/ 14 сентября 2010

Ранее у нас было несколько zip-файлов в нашем веб-приложении.Мы бы хотели сократить конкретный текстовый документ в zip-файле.Это не было проблемой:

URL url = getClass().getResource(zipfile);
ZipFile zip = new ZipFile(url.getFile().replaceAll("%20", " "));     
Entry entry = zip.getEntry("file.txt");

InputStream is = zip.getInputStream(entry);
BufferedReader reader = new BufferedReader(new InputStreamReader(is));

String line = reader.readLine();
while (line != null) {
    // do stuff
}

Однако мы переместили эти zip-файлы в другой модуль и хотим упаковать их в банку.К сожалению, создать ZipFile сейчас не удается.Я могу получить InputStream для почтового индекса: но у меня нет способа получить поток ввода для самой записи.

InputStream is = getClass().getResourceAsStream(zipfile);
ZipInputStream zis = new ZipInputStream(is);

ZipEntry entry = zis.getNextEntry();
while (entry != null && !entry.getName().equals("file.txt")) {
    entry = zis.getNextEntry();
}

, но у меня нет способа получить поток ввода для самой записи.Я попытался найти длину записи и получить следующие n байтов из ZipInputStream, но у меня это не сработало.Казалось, что все прочитанные байты были 0.

Есть ли способ обойти это или мне придется перенести zip-файлы обратно в основной проект?

Ответы [ 4 ]

6 голосов
/ 14 сентября 2010

Как насчет TrueZip?Используя его, вы можете просто открыть заархивированный файл, как если бы он находился внутри каталога.

new FileOutputStream("/path/to/some-jar.jar/internal/zip/file.zip/myfile.txt");

Согласно документам, бесконечное вложение также поддерживается.Я до сих пор не использовал этот проект, но он некоторое время был у меня на радаре и, похоже, применим к вашей проблеме.

Сайт проекта: http://truezip.java.net/ (отредактировано)

4 голосов
/ 14 сентября 2010
Запись

может дать вам входной поток файла внутреннего zip.

InputStream innerzipstream = zip.getInputStream(entry);

Так что вы можете использовать

new ZipInputStream(innerzipstream);

и попросить ZipInputStream извлечь содержимое внутреннего zip-файла (в обычном порядке у вас нет произвольного доступа, потому что это ZipInputStream)

Посмотрите на http://download.oracle.com/javase/1.4.2/docs/api/java/util/zip/ZipInputStream.html

Последовательный почтовый доступ

Поскольку ZipInputStream читает zip-файл из входного потока, он должен выполнять действия в следующем порядке:

// DO THIS for each entry
ZipEntry e = zipInputStreamObj.getNextEntry();
e.getName // and all data
int size = e.getSize(); // the byte count
while (size > 0) {
   size -= zipInputStreamObj.read(...);
}
zipInputStreamObj.closeEntry();
// DO THIS END

zipInputStreamObj.close();

Примечание: Я не знаю, возвращает ли ZipInputStream.getNextEntry () значение null, когда достигнут конец файла zip или нет. Я надеюсь на это, потому что я не знаю другого способа понять, когда больше нет записей.

0 голосов
/ 15 августа 2013

также возможно проанализировать строку и открыть ZipInputStream в другом ZipInputStream и установить запись в файл внутри.

например. у вас есть строка, как указано выше "path / to / some-jar.jar / internal / zip / file.zip / myfile.txt"

private static final String[] zipFiles = new String[] { ".zip", ".jar" };

public static InputStream getResourceAsStream(final String ref) throws IOException {
    String abstractPath = ref.replace("\\", "/");
    if (abstractPath.startsWith("/")) {
        abstractPath = abstractPath.substring(1);
    }
    final String[] pathElements = abstractPath.split("/");
    return getResourceAsStream(null, pathElements);
}

private static InputStream getResourceAsStream(final ZipInputStream parentStream, final String[] pathElements)
        throws IOException {

    if (pathElements.length == 0) return parentStream;

    final StringBuilder nextFile = new StringBuilder();
    for (int index = 0; index < pathElements.length; index++) {
        final String pathElement = pathElements[index];
        nextFile.append((index > 0 ? "/" : "") + pathElement);
        if (pathElement.contains(".")) {
            final String path = nextFile.toString();
            if (checkForZip(pathElement)) {
                final String[] restPath = new String[pathElements.length - index - 1];
                System.arraycopy(pathElements, index + 1, restPath, 0, restPath.length);
                if (parentStream != null) {
                    setZipToEntry(parentStream, path);
                    return getResourceAsStream(new ZipInputStream(parentStream), restPath);
                } else return getResourceAsStream(new ZipInputStream(new FileInputStream(path)), restPath);
            } else {
                if (parentStream != null) {
                    setZipToEntry(parentStream, path);
                    return parentStream;
                } else return new FileInputStream(path);
            }
        }
    }
    throw new FileNotFoundException("File not found: " + nextFile.toString());
}

private static void setZipToEntry(final ZipInputStream in, final String name) throws IOException {
    ZipEntry entry;
    while ((entry = in.getNextEntry()) != null) {
        if (entry.getName().equals(name)) return;
    }
    throw new FileNotFoundException("File not found: " + name);
}

private static boolean checkForZip(final String ref) {
    for (final String zipFile : zipFiles) {
        if (ref.endsWith(zipFile)) return true;
    }
    return false;
}
0 голосов
/ 23 июля 2013

Я изменил код доступа Sequential Zip, указанный выше:

File destFile = new File(destDir, jarName);
JarOutputStream jos = new JarOutputStream(new FileOutputStream(destFile));

JarInputStream jis = new JarInputStream(is);
JarEntry jarEntry = jis.getNextJarEntry();
for (; jarEntry != null ; jarEntry = jis.getNextJarEntry()) {
    jos.putNextEntry(new JarEntry(jarEntry.getName()));
    if(jarEntry.isDirectory()) {
       continue;
    }

    int bytesRead = jis.read(buffer);
    while(bytesRead != -1) {
    jos.write(buffer, 0, bytesRead);
    bytesRead = jis.read(buffer);
    }

}
is.close();
jis.close();
jos.flush();
jos.closeEntry();
jos.close();

В приведенном выше коде я пытаюсь скопировать файл Jar из другого файла Jar в папку в файловой системе. 'is' - это поток ввода в файл jar внутри другого файла jar (jar.getInputStream ("lib / abcd.jar")) *

...