JSP для обслуживания zip-файла повреждает файл
Вопрос
У меня возникла проблема при попытке отправить zip-файл в JSP.
Zip-файл всегда поврежден после завершения загрузки.Я попробовал несколько различных методов чтения и записи, и, похоже, ни один из них не сработал.
Я полагаю, что, вероятно, где-то добавляются символы ascii, поскольку файл откроется и отобразит все имена файлов, но я не могу извлечь ни одного файла.
Вот мой последний код:
<%@ page import= "java.io.*" %>
<%
BufferedReader bufferedReader = null;
String zipLocation = "C:\\zipfile.zip";
try
{
bufferedReader = new BufferedReader(new FileReader(zipLocation));
response.setContentType("application/zip");
response.setHeader( "Content-Disposition", "attachment; filename=zipfile.zip" );
int anInt = 0;
while((anInt = bufferedReader.read()) != -1)
{
out.write(anInt);
}
}
catch(Exception e)
{
e.printStackTrace();
}
%>
Редактировать:Я перенес код на сервлет, но он по-прежнему не работал.Я изменил еще кучу всего, так что вот последний нерабочий код:
public void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException
{
try
{
String templateLocation = Config.getInstance().getString("Site.templateDirectory");
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename=output.zip;");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(baos);
FileInputStream fis = new FileInputStream(templateLocation);
int len;
byte[] buf = new byte[1024];
while ((len = fis.read(buf)) > 0)
{
bos.write(buf, 0, len);
}
bos.close();
PrintWriter pr = response.getWriter();
pr.write(baos.toString());
pr.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
РЕДАКТИРОВАТЬ 2:
Это код сервлета, с которым я на самом деле работаю.Спасибо вам всем!
public void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException
{
try
{
String templateLocation = Config.getInstance().getString("Site.templateDirectory");
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename=output.zip;");
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
FileInputStream fis = new FileInputStream(templateLocation);
int len;
byte[] buf = new byte[1024];
while ((len = fis.read(buf)) > 0)
{
bos.write(buf, 0, len);
}
bos.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
Решение
Zip-файлы являются двоичными файлами и, следовательно, не подходят для передачи в виде символьных данных.Кроме того, текст вне кода может повредить файл.
Используйте простой ванильный сервлет вместо JSP.
Другие советы
JSP добавляет пробелы к выходным данным.Я предлагаю вам перенести это в сервлет.
В качестве альтернативы, вы можете взглянуть на Удалить пробелы из вывода jsp , но я не уверен, что это не повлияет на сам вывод ZIP-файла.
Проблема в этом точном фрагменте находится на второй строке - у вас есть пустая строка за пределами тегов JSP, которая отправляется в браузер в виде HTML (т. е.пустая строка в исходном HTML-файле).
Будьте очень осторожны, чтобы удалить все, чего нет в <% %>, особенно пробелы (даже терминальный перевод строки!), или следуйте советам в другом месте и используйте сервлет :)
Ваш код сервлета не работает, потому что вы выводите свой поток в response.getWriter()
, который , как указывали другие , предназначен для символьные данные.Я цитирую Javadoc:
PrintWriter getWriter() throws IOException
Возвращает объект PrintWriter, который может отправлять клиенту символьный текст.PrintWriter использует кодировку символов, возвращаемую getCharacterEncoding()
Не только это, но вы даже не записываете массив байтов в Writer
, вы пишете результаты ByteArrayOutputStream.toString()
, который также выполняет преобразование символов ~
Вы хотите использовать response.getOutputStream(), что-то вроде:
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
А затем запишите в него байтовое содержимое вашего файла.
Считыватели обычно предназначены для символьных потоков, если я правильно помню - вы могли бы попробовать что-то более похожее на ByteArrayOutputStream?Кроме того, JSP действительно может искажать выходные данные, как прокомментировали другие.
bufferedReader = new BufferedReader(new FileReader(zipLocation));
Помимо проблемы с сервлетом / JSP, эта строка со 100% уверенностью искажает ваши данные.Он попытается интерпретировать двоичные данные как текст, используя кодировку платформы по умолчанию, что означает, что примерно половина байтов в файле заменена на "неизвестный символ".
Байты и строки - это не одно и то же!
Я бы также предложил использовать простой сервлет и рассмотрел бы Ответ Роберта Мунтяну как правильно, но вы могли бы сделать это и в своем JSP.Проблема не в добавленном пробеле, а в том, что неявная переменная "out" является экземпляром JspWriter, а Writer предназначен для символов, а не для байтов.Попробуйте использовать ответ.getOutputStream() и прямо сейчас это должно сработать.Вы получите исключение, в котором говорится, что кто-то другой уже получил OutputStream, но вы можете проигнорировать его.
Но, как я уже сказал, использование Сервлета было бы намного чище.