Записать данные файла как Bzip2 в вывод ответа сервлета

Я пытаюсь заставить Tomcat записать содержимое сервлета в виде файла bzip2 (возможно, глупое требование, но оно, очевидно, необходимо для некоторой работы по интеграции). Я использую Spring Framework, так что это в AbstractController.

Я использую библиотеку bzip2 с http://www.kohsuke.org/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 abstractcontroller

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

Я сделал несколько попыток, используя различные подходы, включая запись непосредственно в ServletOutput, но я довольно озадачен и не могу найти никаких / многих примеров в Интернете.

Любой совет от любого, кто сталкивался с этим прежде, был бы очень признателен. Альтернативные библиотеки / подходы хороши, но, к сожалению, это должен быть bzip2'd.

2 ответа

Решение

Размещенный подход действительно странный. Я переписал так, чтобы это имело больше смысла. Попробуйте.

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 достаточно.

Вы можете найти работу с CompressorStreamFactory из commons-compress немного проще. Это наследник версии Ant, с которой вы уже работаете, и в итоге он на 2 строки отличается от примера 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();
}
Другие вопросы по тегам