将包含多个文件的 Inputstream 放入一个 ZipEntry
Put Inputstream containing multiple files into one ZipEntry
我想将 File
的数组压缩到一个 zip 文件并将其发送到浏览器。每个File
的Inputstream
是一个shapefile,实际上由多个文件(.shp, .dbf, .shx, ...)组成。
当我使用以下代码仅发送一个 File
时,它可以正常工作,并返回一个包含所有所需文件的 zip 文件。
发送单个文件的代码
FileInputStream is = new FileInputStream(files.get(0));
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=" + getCurrentUser(request).getNiscode() + ".zip");
while (is.available() > 0) {
response.getOutputStream().write(is.read());
}
is.close();
if (response.getOutputStream() != null) {
response.getOutputStream().flush();
response.getOutputStream().close();
}
当我尝试将所有文件一起发送时,返回了一个包含所需文件夹的 zip 文件,但在每个文件夹中只存在一个仅具有 .file 扩展名的元素。它与 ZipOutputStream
?
的条目有关
发送所有文件的代码
byte[] zip = this.zipFiles(files, Ids);
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename="test.zip");
response.getOutputStream().write(zip);
response.flushBuffer();
private byte[] zipFiles(ArrayList<File> files, String[] Ids) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos);
int count = 0;
for (File file : files) {
FileInputStream fis = new FileInputStream(file);
zos.putNextEntry(new ZipEntry(Ids[count] + "/"));
zos.putNextEntry(new ZipEntry(Ids[count] + "/" + file.getName()));
while (fis.available() > 0) {
zos.write(fis.read());
}
zos.closeEntry();
fis.close();
count ++;
}
zos.flush();
baos.flush();
zos.close();
baos.close();
return baos.toByteArray();
}
尝试以下解决方案:
private byte[] zipFiles(ArrayList<File> files, String[] Ids) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos);
for (File file : files) {
ZipEntry ze= new ZipEntry(file.getName());
zos.putNextEntry(ze);
FileInputStream fis = new FileInputStream(file);
int len;
while ((len = fis .read(buffer)) > 0) {
zos.write(buffer, 0, len);
}
fis .close();
}
byte[] byteArray = baos.toByteArray();
zos.flush();
baos.flush();
zos.close();
baos.close();
return byteArray;
}
IDK 为什么要放置 count
变量以及为什么放置两次 zos.putNextEntry(new ZipEntry())
。
根据您的代码,您的 files
数组中的每个文件似乎都已经是一个 zip 文件
当您稍后执行 zipFiles
时,您正在制作一个 zip 文件,其文件夹中包含更多 zip 文件。您显然不想要这个,但您想要一个 zip 文件,其中包含包含所有可能 zip 文件内容的文件夹。
基于位于“Reading data from multiple zip files and combining them to one”的 Thanador 的现有答案,我设计了以下解决方案,还包括目录和适当的流处理:
/**
* Combine multiple zipfiles together
* @param files List of file objects pointing to zipfiles
* @param ids List of file names to use in the final output
* @return The byte[] object representing the final output
* @throws IOException When there was a problem reading a zipfile
* @throws NullPointerException When there either input is or contains a null value
*/
private byte[] zipFiles(ArrayList<File> files, String[] ids) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// Buffer to copy multiple bytes at once, this is generally faster that just reading and writing 1 byte at a time like your previous code does
byte[] buf = new byte[16 * 1024];
int length = files.size();
assert length == ids.length;
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
for (int i = 0; i < length; i++) {
try (ZipInputStream inStream = new ZipInputStream(new FileInputStream(files.get(i))) {
ZipEntry entry;
while ((entry = inStream.getNextEntry()) != null) {
zos.putNextEntry(new ZipEntry(ids[i] + "/" + entry.getName()));
int readLength;
while ((readLength = inStream.read(buf)) > 0) {
zos.write(buf, 0, readLength);
}
}
}
}
}
return baos.toByteArray();
}
- 从技术上讲,直接写入从
response.getOutputStream()
获得的输出流会更快、内存效率更高,但我在上面的示例中没有这样做,因此您可以更轻松地实现代码中的方法
- 如果你关闭一个流,它会自动刷新它,我正在使用 try-with-resources 来关闭它们
public static void compressListFiles(List<Pair<String, String>> filePairList, ZipOutputStream zipOut) throws Exception {
for (Pair<String, String> pair : filePairList) {
File fileToZip = new File(pair.getValue());
String fileId = pair.getKey();
FileInputStream fis = new FileInputStream(fileToZip);
ZipEntry zipEntry = new ZipEntry(fileId + "/" + fileToZip.getName());
zipOut.putNextEntry(zipEntry);
byte[] bytes = new byte[1024];
int length;
while ((length = fis.read(bytes)) >= 0) {
zipOut.write(bytes, 0, length);
}
fis.close();
}
}
我想将 File
的数组压缩到一个 zip 文件并将其发送到浏览器。每个File
的Inputstream
是一个shapefile,实际上由多个文件(.shp, .dbf, .shx, ...)组成。
当我使用以下代码仅发送一个 File
时,它可以正常工作,并返回一个包含所有所需文件的 zip 文件。
发送单个文件的代码
FileInputStream is = new FileInputStream(files.get(0));
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=" + getCurrentUser(request).getNiscode() + ".zip");
while (is.available() > 0) {
response.getOutputStream().write(is.read());
}
is.close();
if (response.getOutputStream() != null) {
response.getOutputStream().flush();
response.getOutputStream().close();
}
当我尝试将所有文件一起发送时,返回了一个包含所需文件夹的 zip 文件,但在每个文件夹中只存在一个仅具有 .file 扩展名的元素。它与 ZipOutputStream
?
发送所有文件的代码
byte[] zip = this.zipFiles(files, Ids);
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename="test.zip");
response.getOutputStream().write(zip);
response.flushBuffer();
private byte[] zipFiles(ArrayList<File> files, String[] Ids) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos);
int count = 0;
for (File file : files) {
FileInputStream fis = new FileInputStream(file);
zos.putNextEntry(new ZipEntry(Ids[count] + "/"));
zos.putNextEntry(new ZipEntry(Ids[count] + "/" + file.getName()));
while (fis.available() > 0) {
zos.write(fis.read());
}
zos.closeEntry();
fis.close();
count ++;
}
zos.flush();
baos.flush();
zos.close();
baos.close();
return baos.toByteArray();
}
尝试以下解决方案:
private byte[] zipFiles(ArrayList<File> files, String[] Ids) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos);
for (File file : files) {
ZipEntry ze= new ZipEntry(file.getName());
zos.putNextEntry(ze);
FileInputStream fis = new FileInputStream(file);
int len;
while ((len = fis .read(buffer)) > 0) {
zos.write(buffer, 0, len);
}
fis .close();
}
byte[] byteArray = baos.toByteArray();
zos.flush();
baos.flush();
zos.close();
baos.close();
return byteArray;
}
IDK 为什么要放置 count
变量以及为什么放置两次 zos.putNextEntry(new ZipEntry())
。
根据您的代码,您的 files
数组中的每个文件似乎都已经是一个 zip 文件
当您稍后执行 zipFiles
时,您正在制作一个 zip 文件,其文件夹中包含更多 zip 文件。您显然不想要这个,但您想要一个 zip 文件,其中包含包含所有可能 zip 文件内容的文件夹。
基于位于“Reading data from multiple zip files and combining them to one”的 Thanador 的现有答案,我设计了以下解决方案,还包括目录和适当的流处理:
/**
* Combine multiple zipfiles together
* @param files List of file objects pointing to zipfiles
* @param ids List of file names to use in the final output
* @return The byte[] object representing the final output
* @throws IOException When there was a problem reading a zipfile
* @throws NullPointerException When there either input is or contains a null value
*/
private byte[] zipFiles(ArrayList<File> files, String[] ids) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// Buffer to copy multiple bytes at once, this is generally faster that just reading and writing 1 byte at a time like your previous code does
byte[] buf = new byte[16 * 1024];
int length = files.size();
assert length == ids.length;
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
for (int i = 0; i < length; i++) {
try (ZipInputStream inStream = new ZipInputStream(new FileInputStream(files.get(i))) {
ZipEntry entry;
while ((entry = inStream.getNextEntry()) != null) {
zos.putNextEntry(new ZipEntry(ids[i] + "/" + entry.getName()));
int readLength;
while ((readLength = inStream.read(buf)) > 0) {
zos.write(buf, 0, readLength);
}
}
}
}
}
return baos.toByteArray();
}
- 从技术上讲,直接写入从
response.getOutputStream()
获得的输出流会更快、内存效率更高,但我在上面的示例中没有这样做,因此您可以更轻松地实现代码中的方法 - 如果你关闭一个流,它会自动刷新它,我正在使用 try-with-resources 来关闭它们
public static void compressListFiles(List<Pair<String, String>> filePairList, ZipOutputStream zipOut) throws Exception {
for (Pair<String, String> pair : filePairList) {
File fileToZip = new File(pair.getValue());
String fileId = pair.getKey();
FileInputStream fis = new FileInputStream(fileToZip);
ZipEntry zipEntry = new ZipEntry(fileId + "/" + fileToZip.getName());
zipOut.putNextEntry(zipEntry);
byte[] bytes = new byte[1024];
int length;
while ((length = fis.read(bytes)) >= 0) {
zipOut.write(bytes, 0, length);
}
fis.close();
}
}