即时创建包含CSV文件的ZIP文件

9

我正在尝试动态创建一个zip文件,其中包含一堆csv文件并从servlet返回该文件,但这很令人困惑。需要一些指导。以下是我已经拥有的一些代码片段,它们需要共同协作:

// output stream coming from httpResponse, thats all fine
ZipOutputStream zip = new ZipOutputStream(outputStream);


// using the openCSV library to create the csv file
CSVWriter writer = new CSVWriter(Writer?); 
// what writer do I use? I want to write to memory, not a file

writer.writeNext(entries); 
writer.close();

// at this point should I have the csv file in memory somewhere? 
//and then try to copy it into the zip file?

int length;
byte[] buffer = new byte[1024 * 32];    
zip.putNextEntry(new ZipEntry(getClass() + ".csv"));

// the 'in' doesn't exist yet - where am I getting the input stream from?
while((length = in.read(buffer)) != -1)
    zip.write(buffer, 0, length);

zip.closeEntry();
zip.flush();

一个 ByteArrayOutputStream - fge
作者使用 writer 参数而不是输出流 - 我可以将其包装在 printWriter 中吗? - ant-depalma
这篇回答可能会有所帮助:https://dev59.com/Y2ULtIcB2Jgan1zniGI5#68492465 - Kim Gentes
1个回答

14

您可以按照以下方式流式传输包含CSV的ZIP文件:

try {
    OutputStream servletOutputStream = httpServletResponse.getOutputStream(); // retrieve OutputStream from HttpServletResponse
    ZipOutputStream zos = new ZipOutputStream(servletOutputStream); // create a ZipOutputStream from servletOutputStream

    List<String[]> csvFileContents  = getContentToZIP(); // get the list of csv contents. I am assuming the CSV content is generated programmatically
    int count = 0;
    for (String[] entries : csvFileContents) {
        String filename = "file-" + ++count  + ".csv";
        ZipEntry entry = new ZipEntry(filename); // create a zip entry and add it to ZipOutputStream
        zos.putNextEntry(entry);

        CSVWriter writer = new CSVWriter(new OutputStreamWriter(zos));  // There is no need for staging the CSV on filesystem or reading bytes into memory. Directly write bytes to the output stream.
        writer.writeNext(entries);  // write the contents
        writer.flush(); // flush the writer. Very important!
        zos.closeEntry(); // close the entry. Note : we are not closing the zos just yet as we need to add more files to our ZIP
    }

    zos.close(); // finally closing the ZipOutputStream to mark completion of ZIP file
} catch (Exception e) {
    log.error(e); // handle error
}

当然可以,但是我从来没有在任何地方调用writer.close,这样可以吗? - ant-depalma
是的,作者正在直接向Servlet的outputstream写入字节。如果你注意到了,在整个代码中都在使用相同的流。当你完成写入时,只需要关闭一次即可。我们在代码的稍后部分执行此操作,就在catch块之前。 - nadirsaghar
@nadirsaghar,你能告诉我 getContentToZIP(); 方法是从哪里得到的吗?我在网上找不到它。 - Tan
生成一个大小为30MB的zip文件(其中包含多个CSV文件)需要多长时间? - NobesInd
1
如果有人遇到和我一样的问题:我在这个项目中使用了javacsv库而不是opencsv,与opencsv不同的是,javacsv中的CsvWriter类在其finalize()方法中包含对close()的调用,因此当CsvWriter被垃圾回收时,它可能会提前关闭ZipOutputStream,从而导致“流已关闭”错误。 - ahiijny
有没有办法在流/压缩过程中通知客户端发生错误?似乎进入catch块不会影响响应以指示除关闭资源之外的任何内容,因为响应已经提交!!! - Anddo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接