将文件数据写为Bzip2以输出servlet响应

时间:2010-02-19 21:33:05

标签: java spring servlets compression bzip2

我正在尝试让Tomcat将servlet内容写成bzip2文件(或许是愚蠢的要求,但显然有些集成工作是必要的)。我正在使用Spring框架,因此它位于AbstractController中。

我正在使用http://www.kohsuke.org/bzip2/

中的bzip2库

我可以将内容压缩得很好但是当文件被写出来时,它似乎包含一堆元数据并且无法识别为bzip2文件。

这就是我正在做的事情

// get the contents of my file as a byte array
byte[] fileData =  file.getStoredFile();

ByteArrayOutputStream baos = new ByteArrayOutputStream();

//create a bzip2 output stream to the byte output and write the file data to it             
CBZip2OutputStream bzip = null;
try {
     bzip = new CBZip2OutputStream(baos);
     bzip.write(fileData, 0, fileData.length);
     bzip.close();  
} catch (IOException ex) {
     ex.printStackTrace();
}
byte[] bzippedOutput = baos.toByteArray();
System.out.println("bzipcompress_output:\t" + bzippedOutput.length);

//now write the byte output to the servlet output
//setting content disposition means the file is downloaded rather than displayed
int outputLength = bzippedOutput.length;
String fileName = file.getFileIdentifier();
response.setBufferSize(outputLength);
response.setContentLength(outputLength);
response.setContentType("application/x-bzip2");
response.setHeader("Content-Disposition",
                                       "attachment; filename="+fileName+";)");

这是从Spring abstractcontroller

中的以下方法调用的
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)  throws Exception

我用不同的方法对它进行了一些尝试,包括直接写入ServletOutput,但我很难过,在网上找不到任何/很多例子。

任何遇到过这种情况的人的建议都会非常感激。替代库/方法很好,但不幸的是它必须是bzip2'd。

2 个答案:

答案 0 :(得分:3)

发布的方法确实很奇怪。我改写了以便更有意义。试一试。

String fileName = file.getFileIdentifier();
byte[] fileData = file.getStoredFile(); // BTW: Any chance to get this as InputStream? This is namely memory hogging.

response.setContentType("application/x-bzip2");
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");

OutputStream output = null;

try {
     output = new CBZip2OutputStream(response.getOutputStream());
     output.write(fileData);
} finally {
     output.close();
}

您会看到,只需使用CBZip2OutputStream打包回复的输出流,然后将byte[]写入其中。

您可能会在服务器日志中看到IllegalStateException: Response already committed之后(顺便发送下载正确),这意味着Spring之后尝试转发请求/响应。我不做Spring,所以我不能详细说明,但你应该至少指示Spring 远离来回应。不要让它做映射,转发或其他。我认为返回null就足够了。

答案 1 :(得分:2)

您可能会发现CompressorStreamFactory commons-compress更容易使用{{3}}。它是你已经使用过的Ant版本的一个版本,最终有两行不同于BalusC的例子。

或多或少是图书馆偏好的问题。

OutputStream out = null;
try {
    out = new CompressorStreamFactory().createCompressorOutputStream("bzip2", response.getOutputStream());
    IOUtils.copy(new FileInputStream(input), out); // assuming you have access to a File.
} finally {
    out.close();
}