将文件数据作为 Bzip2 写入 servlet 响应的输出

发布于 2024-08-23 00:49:21 字数 1682 浏览 9 评论 0原文

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

正在使用 http://www.kohsuke.org/bzip2/ 中的 bzip2 库

我 可以很好地对内容进行 bzip 压缩,但是当文件写出时,它似乎包含一堆元数据,并且无法识别为 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 抽象控制器中的以下方法调用的

protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)  throws Exception

我已经用不同的方法对其进行了一些尝试,包括直接写入 ServletOutput 但我很困惑并且找不到任何/网上很多例子。

任何以前遇到过此问题的人的任何建议将不胜感激。替代库/方法很好,但不幸的是它必须是 bzip2 的。

I'm trying to get Tomcat to write out the servlet contents as a bzip2 file (Silly requirement perhaps but it's apparently necessary for some integration work). I'm using the Spring framework so this is in an AbstractController.

I'm using the bzip2 library from http://www.kohsuke.org/bzip2/

I can get the contents bzipped fine but when the file is written out it seems to contain a bunch of meta data and is unrecognisable as a bzip2 file.

Here's what I'm doing

// 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+";)");

This is being called from the following method in the Spring abstractcontroller

protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)  throws Exception

I've taken a few stabs at it in different approaches, including writing directly to the ServletOutput but I'm pretty stumped and can't find any/many examples online.

Any advice from anyone who's come across this before would be much appreciated. Alternative libraries/approaches are fine, but unfortunately it must be bzip2'd.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

沒落の蓅哖 2024-08-30 00:49:22

发布的方法确实很奇怪。我已经重写,使其更有意义。尝试一下。

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已经提交 (顺便说一句,下载已正确发送),那么这意味着 Spring 之后正在尝试转发请求/响应。我不做 Spring,所以我无法详细介绍,但您至少应该指示 Spring 远离响应。不要让它进行映射、转发或其他任何操作。我认为返回 null 就足够了。

The posted approach is indeed weird. I've rewritten so that it makes more sense. Give it a try.

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();
}

You see, just wrap the output stream of the response with CBZip2OutputStream and write the byte[] to it.

You may happen to see IllegalStateException: Response already committed coming after this in the server logs (with the download being correctly sent by the way), then it means that Spring is trying to forward the request/response afterwards. I don't do Spring, so I can't go in detail, but you should at least instruct Spring to stay away from the response. Do not let it do a mapping, forward or whatever. I think returning null suffices.

晨与橙与城 2024-08-30 00:49:22

您可能会发现使用 CompressorStreamFactory来自 commons-compress 更容易一些。它是您已经使用的 Ant 版本的后代,最终与 BalusC 的示例有 2 行不同。

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

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();
}

You might find working with CompressorStreamFactory from commons-compress a little easier. It's a decedent of the Ant version you're already working with and ends up 2 lines different from BalusC's example.

More or less a matter of library preference.

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();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文