java 读取 jar 文件中的 zip 文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3710615/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Reading a zip file within a jar file
提问by samblake
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:
以前,我们的 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
}
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.
然而,我们已经将这些 zip 文件移动到另一个模块中,并希望将它们打包在一个 jar 中。不幸的是,创建ZipFile
现在失败了。我可以得到一个InputStream
zip: 但我无法获得条目本身的输入流。
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.
但我无法获得条目本身的输入流。我尝试找到条目的长度并从中获取接下来的 n 个字节,ZipInputStream
但这对我不起作用。似乎所有读取的字节都是 0。
Is there a way round this or am I going to have to move the zip files back into the core project?
有没有办法解决这个问题,还是我必须将 zip 文件移回核心项目?
采纳答案by helios
entry can give you the inputstream of the inner-zip file.
entry 可以为您提供内部 zip 文件的输入流。
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)
并要求 ZipInputStream 检索内部 zip 文件的内容(以有序的方式,您没有随机访问,因为它是一个 ZipInputStream)
Look at http://download.oracle.com/javase/1.4.2/docs/api/java/util/zip/ZipInputStream.html
查看http://download.oracle.com/javase/1.4.2/docs/api/java/util/zip/ZipInputStream.html
Sequential zip access
顺序 zip 访问
As ZipInputStream is reading a zip file from an input stream it has to do things in order:
当 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();
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.
注意:当到达 zip 文件末尾时,我不知道 ZipInputStream.getNextEntry() 是否返回 null。我希望如此,因为当没有更多条目时,我不知道其他方式来实现。
回答by Andy
How about TrueZip? Using it you could simply open the zipped file as if it was located inside a directory.
TrueZip 怎么样?使用它,您可以简单地打开压缩文件,就像它位于目录中一样。
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)
项目站点:http: //truezip.java.net/(已编辑)
回答by Tilak Sharma
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"))
在上面的代码中,我试图将另一个 Jar 文件中的 Jar 文件复制到文件系统中的文件夹中。'is' 是另一个 jar 文件中 jar 文件的输入流 (jar.getInputStream("lib/abcd.jar"))
回答by Ben
it is also possible to parse the string and open an ZipInputStream on another ZipInputStream and set the entry to the file inside.
也可以解析字符串并在另一个 ZipInputStream 上打开一个 ZipInputStream 并将条目设置为里面的文件。
e.g. you have the String like above "path/to/some-jar.jar/internal/zip/file.zip/myfile.txt"
例如你有像上面这样的字符串“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;
}