以前我们的网络应用程序中有一些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
现在失败了。我可以获得一个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();
}
但我无法获得条目本身的输入流。我尝试找到条目的长度并从ZipInputStream
获取下一个n字节,但这对我不起作用。似乎读取的所有字节都是0。
有没有办法解决这个问题,还是我必须将zip文件移回核心项目?
答案 0 :(得分:6)
TrueZip怎么样?使用它,您只需打开压缩文件,就好像它位于目录中一样。
new FileOutputStream("/path/to/some-jar.jar/internal/zip/file.zip/myfile.txt");
根据文档,还支持无限嵌套。我还没有真正使用这个项目,但它已经在我的雷达上了一段时间,它似乎适用于你的问题。
项目现场:http://truezip.java.net/(已编辑)
答案 1 :(得分:4)
条目可以为您提供inner-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
顺序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();
注意:我不知道ZipInputStream.getNextEntry()是否在到达zip文件末尾时返回null。我希望如此,因为当没有更多条目时,我不知道其他方式。
答案 2 :(得分:0)
我修改了上面提供的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”))
答案 3 :(得分:0)
也可以解析字符串并在另一个ZipInputStream上打开ZipInputStream,并将条目设置为内部文件。
e.g。你有上面的字符串" 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;
}