JSP для обслуживания zip-файла повреждает файл

StackOverflow https://stackoverflow.com/questions/1017736

  •  06-07-2019
  •  | 
  •  

Вопрос

У меня возникла проблема при попытке отправить 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, но вы можете проигнорировать его.

Но, как я уже сказал, использование Сервлета было бы намного чище.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top