读取 jar 文件中的 zip 文件

发布于 2024-09-19 10:20:13 字数 975 浏览 10 评论 0原文

之前我们的 Web 应用程序中有一些 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 文件移动到另一个模块中,并希望将它们打包在一个 jar 中。不幸的是,创建 ZipFile 现在失败。我可以获得 zip 的 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();
}

但我无法获取条目本身的输入流。我尝试查找条目的长度并从 ZipInputStream 获取接下来的 n 个字节,但这对我不起作用。看起来所有读取的字节都是 0。

有没有办法解决这个问题,或者我是否必须将 zip 文件移回到核心项目中?

Previously we had some zip files within our web application. We would want to pares a specific text document within the zip file. This wasn't a problem:

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
}

However we've moved these zip files into another module and want to package them within a jar. Unfortunately, creating the ZipFile now fails. I can get an InputStream for the zip: but I have no way of getting an input stream for the entry itself.

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();
}

but I have no way of getting an input stream for the entry itself. I tried finding the length of the entry and getting the next n bytes from the ZipInputStream but this didn't work for me. It seemed all bytes read were 0.

Is there a way round this or am I going to have to move the zip files back into the core project?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

最美不过初阳 2024-09-26 10:20:13

TrueZip 怎么样?使用它,您可以简单地打开压缩文件,就好像它位于目录中一样。

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

根据文档,还支持无限嵌套。我还没有实际使用这个项目,但它已经出现在我的雷达上一段时间了,它似乎适用于你的问题。

项目站点:http://truezip.java.net/(已编辑)

How about TrueZip? Using it you could simply open the zipped file as if it was located inside a directory.

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

According to the docs, infinite nesting is also supported. I have yet to actually use this project, but it's been on my radar for a while and it seems applicable to your problem.

Project Site: http://truezip.java.net/ (edited)

じее 2024-09-26 10:20:13

条目可以为您提供内部 zip 文件的输入流。

InputStream innerzipstream = zip.getInputStream(entry);

因此,您可以使用

new ZipInputStream(innerzipstream);

并要求 ZipInputStream 检索内部 zip 文件的内容(以有序的方式,您不能随机访问,因为它是 ZipInputStream)

。 oracle.com/javase/1.4.2/docs/api/java/util/zip/ZipInputStream.html" rel="nofollow noreferrer">http://download.oracle.com/javase/1.4.2/docs/api /java/util/zip/ZipInputStream.html

顺序 zip 访问

由于 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();

注意: 我不知道当到达 zip 文件末尾时 ZipInputStream.getNextEntry() 是否返回 null。我希望如此,因为当没有更多条目时我不知道其他方式来实现。

entry can give you the inputstream of the inner-zip file.

InputStream innerzipstream = zip.getInputStream(entry);

So you can use

new ZipInputStream(innerzipstream);

and ask the ZipInputStream to retrieve the content of the inner-zip-file (in an ordered fashion, you don't have random access because it's a ZipInputStream)

Look at http://download.oracle.com/javase/1.4.2/docs/api/java/util/zip/ZipInputStream.html

Sequential zip access

As ZipInputStream is reading a zip file from an input stream it has to do things in order:

// 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();

Note: I don't know if ZipInputStream.getNextEntry() returns null when end of zip file is reached or not. I hope so because I don't know other way to realize when there are no more entries.

他夏了夏天 2024-09-26 10:20:13

我修改了上面提供的 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"))

I have modified the Sequential Zip access code provided above:

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();

In the above code, I am trying to copy a Jar file inside another Jar file to a folder in file system.
'is' is the input stream to the jar file inside another jar file (jar.getInputStream("lib/abcd.jar"))

送你一个梦 2024-09-26 10:20:13

也可以解析字符串并在另一个 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;
}

it is also possible to parse the string and open an ZipInputStream on another ZipInputStream and set the entry to the file inside.

e.g. you have the String like above "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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文