如何创建多部分 zip 文件并读回?
How to create a multipart zip file and read it back?
我如何正确地 zip 字节到 ByteArrayOutputStream
然后使用 ByteArrayInputStream
读取它?我有以下方法:
private byte[] getZippedBytes(final String fileName, final byte[] input) throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ZipOutputStream zipOut = new ZipOutputStream(bos);
ZipEntry entry = new ZipEntry(fileName);
entry.setSize(input.length);
zipOut.putNextEntry(entry);
zipOut.write(input, 0, input.length);
zipOut.closeEntry();
zipOut.close();
//Turn right around and unzip what we just zipped
ZipInputStream zipIn = new ZipInputStream(new ByteArrayInputStream(bos.toByteArray()));
while((entry = zipIn.getNextEntry()) != null) {
assert entry.getSize() >= 0;
}
return bos.toByteArray();
}
当我执行这段代码时,底部的断言失败了,因为entry.size
是-1
。我不明白为什么提取的实体与压缩的实体不匹配。
为什么大小是-1?
调用 getNextEntry
in a ZipInputStream
只需将阅读光标定位在要阅读的条目的开头。
大小(连同其他元数据)存储在实际数据的末尾,因此当光标位于开头时不容易获得。
这些信息只有在您阅读整个条目数据或转到下一个条目后才可用。
例如,转到下一个条目:
// position at the start of the first entry
entry = zipIn.getNextEntry();
ZipEntry firstEntry = entry;
// size is not yet available
System.out.println("before " + firstEntry.getSize()); // prints -1
// position at the start of the second entry
entry = zipIn.getNextEntry();
// size is now available
System.out.println("after " + firstEntry.getSize()); // prints the size
或读取整个条目数据:
// position at the start of the first entry
entry = zipIn.getNextEntry();
// size is not yet available
System.out.println("before " + entry.getSize()); // prints -1
// read the whole entry data
while(zipIn.read() != -1);
// size is now available
System.out.println("after " + entry.getSize()); // prints the size
你的误解很常见,关于这个问题有很多错误报告(已关闭为 "Not an Issue"),比如 JDK-4079029,
JDK-4113731, JDK-6491622.
如错误报告中所述,您可以使用 ZipFile
instead of ZipInputStream
which would allow to reach the size information prior to access the entry data; but to create a ZipFile
you need a File
(请参阅构造函数)而不是字节数组。
例如:
File file = new File( "test.zip" );
ZipFile zipFile = new ZipFile(file);
Enumeration enumeration = zipFile.entries();
while (enumeration.hasMoreElements()) {
ZipEntry zipEntry = (ZipEntry) enumeration.nextElement();
System.out.println(zipEntry.getSize()); // prints the size
}
如何从输入流中获取数据?
如果你想检查解压缩的数据是否等于原始输入数据,你可以像这样从输入流中读取:
byte[] output = new byte[input.length];
entry = zipIn.getNextEntry();
zipIn.read(output);
System.out.println("Are they equal? " + Arrays.equals(input, output));
// and if we want the size
zipIn.getNextEntry(); // or zipIn.read();
System.out.println("and the size is " + entry.getSize());
现在 output
的内容应该与 input
相同。
如何压缩 byte[]
并解压缩?
我经常使用以下方法 deflate/inflate (zip/unzip) 小 byte[]
(即当它适合内存时)。它是根据example given in the Deflater
javadoc and uses Deflater
class to compress data and Inflater
class解压回来的:
public static byte[] compress(byte[] source, int level) {
Deflater compresser = new Deflater(level);
compresser.setInput(source);
compresser.finish();
byte[] buf = new byte[1024];
ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
int n;
while ((n = compresser.deflate(buf)) > 0)
bos.write(buf, 0, n);
compresser.end();
return bos.toByteArray(); // You could as well return "bos" directly
}
public static byte[] uncompress(byte[] source) {
Inflater decompresser = new Inflater();
decompresser.setInput(source);
byte[] buf = new byte[1024];
ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
try {
int n;
while ((n = decompresser.inflate(buf)) > 0)
bos.write(buf, 0, n);
return bos.toByteArray();
} catch (DataFormatException e) {
return null;
} finally {
decompresser.end();
}
}
不需要 ByteArrayInputStream
,但如果您确实需要,可以使用 InflaterInputStream
包装它(但直接使用 Inflater
更容易)。
我如何正确地 zip 字节到 ByteArrayOutputStream
然后使用 ByteArrayInputStream
读取它?我有以下方法:
private byte[] getZippedBytes(final String fileName, final byte[] input) throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ZipOutputStream zipOut = new ZipOutputStream(bos);
ZipEntry entry = new ZipEntry(fileName);
entry.setSize(input.length);
zipOut.putNextEntry(entry);
zipOut.write(input, 0, input.length);
zipOut.closeEntry();
zipOut.close();
//Turn right around and unzip what we just zipped
ZipInputStream zipIn = new ZipInputStream(new ByteArrayInputStream(bos.toByteArray()));
while((entry = zipIn.getNextEntry()) != null) {
assert entry.getSize() >= 0;
}
return bos.toByteArray();
}
当我执行这段代码时,底部的断言失败了,因为entry.size
是-1
。我不明白为什么提取的实体与压缩的实体不匹配。
为什么大小是-1?
调用 getNextEntry
in a ZipInputStream
只需将阅读光标定位在要阅读的条目的开头。
大小(连同其他元数据)存储在实际数据的末尾,因此当光标位于开头时不容易获得。
这些信息只有在您阅读整个条目数据或转到下一个条目后才可用。
例如,转到下一个条目:
// position at the start of the first entry
entry = zipIn.getNextEntry();
ZipEntry firstEntry = entry;
// size is not yet available
System.out.println("before " + firstEntry.getSize()); // prints -1
// position at the start of the second entry
entry = zipIn.getNextEntry();
// size is now available
System.out.println("after " + firstEntry.getSize()); // prints the size
或读取整个条目数据:
// position at the start of the first entry
entry = zipIn.getNextEntry();
// size is not yet available
System.out.println("before " + entry.getSize()); // prints -1
// read the whole entry data
while(zipIn.read() != -1);
// size is now available
System.out.println("after " + entry.getSize()); // prints the size
你的误解很常见,关于这个问题有很多错误报告(已关闭为 "Not an Issue"),比如 JDK-4079029, JDK-4113731, JDK-6491622.
如错误报告中所述,您可以使用 ZipFile
instead of ZipInputStream
which would allow to reach the size information prior to access the entry data; but to create a ZipFile
you need a File
(请参阅构造函数)而不是字节数组。
例如:
File file = new File( "test.zip" );
ZipFile zipFile = new ZipFile(file);
Enumeration enumeration = zipFile.entries();
while (enumeration.hasMoreElements()) {
ZipEntry zipEntry = (ZipEntry) enumeration.nextElement();
System.out.println(zipEntry.getSize()); // prints the size
}
如何从输入流中获取数据?
如果你想检查解压缩的数据是否等于原始输入数据,你可以像这样从输入流中读取:
byte[] output = new byte[input.length];
entry = zipIn.getNextEntry();
zipIn.read(output);
System.out.println("Are they equal? " + Arrays.equals(input, output));
// and if we want the size
zipIn.getNextEntry(); // or zipIn.read();
System.out.println("and the size is " + entry.getSize());
现在 output
的内容应该与 input
相同。
如何压缩 byte[]
并解压缩?
我经常使用以下方法 deflate/inflate (zip/unzip) 小 byte[]
(即当它适合内存时)。它是根据example given in the Deflater
javadoc and uses Deflater
class to compress data and Inflater
class解压回来的:
public static byte[] compress(byte[] source, int level) {
Deflater compresser = new Deflater(level);
compresser.setInput(source);
compresser.finish();
byte[] buf = new byte[1024];
ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
int n;
while ((n = compresser.deflate(buf)) > 0)
bos.write(buf, 0, n);
compresser.end();
return bos.toByteArray(); // You could as well return "bos" directly
}
public static byte[] uncompress(byte[] source) {
Inflater decompresser = new Inflater();
decompresser.setInput(source);
byte[] buf = new byte[1024];
ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
try {
int n;
while ((n = decompresser.inflate(buf)) > 0)
bos.write(buf, 0, n);
return bos.toByteArray();
} catch (DataFormatException e) {
return null;
} finally {
decompresser.end();
}
}
不需要 ByteArrayInputStream
,但如果您确实需要,可以使用 InflaterInputStream
包装它(但直接使用 Inflater
更容易)。