从 ZipInputStream 获取特定文件
Getting specific file from ZipInputStream
我可以完成 ZipInputStream
,但在开始迭代之前,我想获取迭代期间需要的特定文件。我该怎么做?
ZipInputStream zin = new ZipInputStream(myInputStream)
while ((entry = zin.getNextEntry()) != null)
{
println entry.getName()
}
看看Finding a file in zip entry
ZipFile file = new ZipFile("file.zip");
ZipInputStream zis = searchImage("foo.png", file);
public searchImage(String name, ZipFile file)
{
for (ZipEntry e : file.entries){
if (e.getName().endsWith(name)){
return file.getInputStream(e);
}
}
return null;
}
在 ZipEntry 上使用 getName() 方法获取您想要的文件。
ZipInputStream zin = new ZipInputStream(myInputStream)
String myFile = "foo.txt";
while ((entry = zin.getNextEntry()) != null)
{
if (entry.getName().equals(myFileName)) {
// process your file
// stop looking for your file - you've already found it
break;
}
}
从 Java 7 开始,如果您只需要一个文件并且有一个文件可供读取,则最好使用 ZipFile 而不是 ZipStream:
ZipFile zfile = new ZipFile(aFile);
String myFile = "foo.txt";
ZipEntry entry = zfile.getEntry(myFile);
if (entry) {
// process your file
}
如果您正在使用的 myInputStream
来自磁盘上的真实文件,那么您可以简单地使用 java.util.zip.ZipFile
代替,它由 RandomAccessFile
支持并提供直接访问按名称添加到 zip 条目。但是,如果您只有一个 InputStream
(例如,如果您在从网络套接字或类似设备接收到数据后直接处理流),那么您将不得不自己进行缓冲。
您可以将流复制到临时文件,然后使用 ZipFile
打开该文件,或者如果您事先知道数据的最大大小(例如,对于声明其 Content-Length
前面)你可以使用 BufferedInputStream
在内存中缓冲它,直到你找到所需的条目。
BufferedInputStream bufIn = new BufferedInputStream(myInputStream);
bufIn.mark(contentLength);
ZipInputStream zipIn = new ZipInputStream(bufIn);
boolean foundSpecial = false;
while ((entry = zin.getNextEntry()) != null) {
if("special.txt".equals(entry.getName())) {
// do whatever you need with the special entry
foundSpecial = true;
break;
}
}
if(foundSpecial) {
// rewind
bufIn.reset();
zipIn = new ZipInputStream(bufIn);
// ....
}
(我自己没有测试过这段代码,您可能会发现有必要在 bufIn
和第一个 zipIn
之间使用类似 commons-io CloseShieldInputStream
的东西,允许第一个 zip 流关闭而不关闭底层 bufIn
,然后再回绕它。
我迟到了,但以上所有“答案”都没有回答问题,接受的“答案”建议创建效率低下的临时文件。
让我们创建示例 zip 文件:
seq 10000 | sed "s/^.*$/a/"> /tmp/a
seq 10000 20000 | sed "s/^.*$/b/"> /tmp/b
seq 20000 30000 | sed "s/^.*$/c/"> /tmp/c
zip /tmp/out.zip /tmp/a /tmp/b /tmp/c
所以现在我们有 /tmp/out.zip
个文件,其中包含 3 个文件,每个文件都包含字符 a、b 或 c。
现在让我们阅读它:
public static void main(String[] args) throws IOException {
ZipInputStream zipStream = new ZipInputStream(new FileInputStream("/tmp/out.zip"));
ZipEntry zipEntry;
while ((zipEntry = zipStream.getNextEntry()) != null) {
String name = zipEntry.getName();
System.out.println("Entry: "+name);
if (name.equals("tmp/c")) {
byte[] bytes = zipStream.readAllBytes();
String s = new String(bytes);
System.out.println(s);
}
}
}
方法readAllBytes
看起来很奇怪,虽然我们正在处理流,但它似乎有效,我也在一些图像上测试过它,那里失败的可能性更高。所以它可能只是不直观 api,但它似乎有效。
我可以完成 ZipInputStream
,但在开始迭代之前,我想获取迭代期间需要的特定文件。我该怎么做?
ZipInputStream zin = new ZipInputStream(myInputStream)
while ((entry = zin.getNextEntry()) != null)
{
println entry.getName()
}
看看Finding a file in zip entry
ZipFile file = new ZipFile("file.zip");
ZipInputStream zis = searchImage("foo.png", file);
public searchImage(String name, ZipFile file)
{
for (ZipEntry e : file.entries){
if (e.getName().endsWith(name)){
return file.getInputStream(e);
}
}
return null;
}
在 ZipEntry 上使用 getName() 方法获取您想要的文件。
ZipInputStream zin = new ZipInputStream(myInputStream)
String myFile = "foo.txt";
while ((entry = zin.getNextEntry()) != null)
{
if (entry.getName().equals(myFileName)) {
// process your file
// stop looking for your file - you've already found it
break;
}
}
从 Java 7 开始,如果您只需要一个文件并且有一个文件可供读取,则最好使用 ZipFile 而不是 ZipStream:
ZipFile zfile = new ZipFile(aFile);
String myFile = "foo.txt";
ZipEntry entry = zfile.getEntry(myFile);
if (entry) {
// process your file
}
如果您正在使用的 myInputStream
来自磁盘上的真实文件,那么您可以简单地使用 java.util.zip.ZipFile
代替,它由 RandomAccessFile
支持并提供直接访问按名称添加到 zip 条目。但是,如果您只有一个 InputStream
(例如,如果您在从网络套接字或类似设备接收到数据后直接处理流),那么您将不得不自己进行缓冲。
您可以将流复制到临时文件,然后使用 ZipFile
打开该文件,或者如果您事先知道数据的最大大小(例如,对于声明其 Content-Length
前面)你可以使用 BufferedInputStream
在内存中缓冲它,直到你找到所需的条目。
BufferedInputStream bufIn = new BufferedInputStream(myInputStream);
bufIn.mark(contentLength);
ZipInputStream zipIn = new ZipInputStream(bufIn);
boolean foundSpecial = false;
while ((entry = zin.getNextEntry()) != null) {
if("special.txt".equals(entry.getName())) {
// do whatever you need with the special entry
foundSpecial = true;
break;
}
}
if(foundSpecial) {
// rewind
bufIn.reset();
zipIn = new ZipInputStream(bufIn);
// ....
}
(我自己没有测试过这段代码,您可能会发现有必要在 bufIn
和第一个 zipIn
之间使用类似 commons-io CloseShieldInputStream
的东西,允许第一个 zip 流关闭而不关闭底层 bufIn
,然后再回绕它。
我迟到了,但以上所有“答案”都没有回答问题,接受的“答案”建议创建效率低下的临时文件。
让我们创建示例 zip 文件:
seq 10000 | sed "s/^.*$/a/"> /tmp/a
seq 10000 20000 | sed "s/^.*$/b/"> /tmp/b
seq 20000 30000 | sed "s/^.*$/c/"> /tmp/c
zip /tmp/out.zip /tmp/a /tmp/b /tmp/c
所以现在我们有 /tmp/out.zip
个文件,其中包含 3 个文件,每个文件都包含字符 a、b 或 c。
现在让我们阅读它:
public static void main(String[] args) throws IOException {
ZipInputStream zipStream = new ZipInputStream(new FileInputStream("/tmp/out.zip"));
ZipEntry zipEntry;
while ((zipEntry = zipStream.getNextEntry()) != null) {
String name = zipEntry.getName();
System.out.println("Entry: "+name);
if (name.equals("tmp/c")) {
byte[] bytes = zipStream.readAllBytes();
String s = new String(bytes);
System.out.println(s);
}
}
}
方法readAllBytes
看起来很奇怪,虽然我们正在处理流,但它似乎有效,我也在一些图像上测试过它,那里失败的可能性更高。所以它可能只是不直观 api,但它似乎有效。