【问题标题】:Downloading a zip file returns a corrupt zip using servlets使用 servlet 下载 zip 文件会返回损坏的 zip
【发布时间】:2010-08-17 14:53:53
【问题描述】:

我正在尝试使用 servlet 创建一个 zip 文件,但它返回给我一个损坏的 zip 文件,这是我正在创建 zip 的 zipcontents 函数中的代码,有人可以帮助我吗?提前致谢。

public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException,
    IOException {

    ByteArrayOutputStream bout = new ByteArrayOutputStream();
    res.setContentType("application/zip");
    res.setHeader("Content-Disposition", "attachment; filename=output.zip;");

    fsep = File.separator;
    rootDir = new File(getServletContext().getRealPath("Projects" + File.separator + "amrurta"));
    File list[] = rootDir.listFiles();
    zos = new ZipOutputStream(bout);
    zipContents(list, rootDir.getName() + fsep);
    zos.close();
    res.getWriter().println(bout.toString());
}

public void zipContents(File[] file, String dir) {
    // dir - directory in the zip file
    byte[] buffer = new byte[4096];
    try {

        for (int i = 0; i < file.length; i++) { // zip files
            if (file[i].isFile()) {
                fis = new FileInputStream(file[i]);
                zos.putNextEntry(new ZipEntry(dir + file[i].getName()));
                // shows how its stored
                // System.out.println(dir+file[i].getName());
                int bytes_read;
                while ((bytes_read = fis.read(buffer)) != -1)
                    zos.write(buffer, 0, bytes_read);

                fis.close();
            }
        } // for

        // create empty dir if theres no files inside
        if (file.length == 1)
            zos.putNextEntry(new ZipEntry(dir + fsep)); // this part is erroneous i think

        for (int i = 0; i < file.length; i++) { // zip directories
            if (file[i].isDirectory()) {
                File subList[] = file[i].listFiles();

                // for dir of varying depth
                File unparsedDir = file[i];
                String parsedDir = fsep + file[i].getName() + fsep; // last folder
                while (!unparsedDir.getParentFile().getName().equals(rootDir.getName())) {
                    unparsedDir = file[i].getParentFile();
                    parsedDir = fsep + unparsedDir.getName() + parsedDir;
                }
                parsedDir = rootDir.getName() + parsedDir; // add input_output as root

                zipContents(subList, parsedDir);
            }
        } // for

    } catch (IOException ioex) {
        ioex.printStackTrace();
    }
}

【问题讨论】:

    标签: java servlets zip download


    【解决方案1】:

    代码有太多问题。主要的有:

    1. zos 被声明为 servlet 实例变量。这不是线程安全的。它在多个请求之间共享。您冒着后续请求在未完成时覆盖前一个请求的风险。

    2. 二进制 ZIP 内容已转换为带有 bout.toString() 的字符数据。这肯定会损坏二进制数据。您应该使用通常的InputStream#read()/OutputStream#write() 循环将二进制数据写入二进制数据。

    3. 代码不会在每个条目的末尾调用zos.closeEntry()

    我认为#2 是主要原因。你不需要ByteArrayOutputStream。这只是不必要的内存占用。只需将response.getOutputStream() 包裹在ZipOutputStream 中即可。

    ZipOutputStream output = new ZipOutputStream(response.getOutputStream());
    zipFiles(directory.listFiles(), output);
    output.close();
    

    【讨论】:

      【解决方案2】:

      另一个可能的原因是应用服务器的不同 JVM 版本和编译 servlet 的编译器。 非常罕见的问题,但很难理解。

      【讨论】:

        【解决方案3】:

        你可以这样创作 ZipOutputStream zipOut = new ZipOutputStream(res. getOutputStream()); 并且您写入 zip 条目的每个 zip 条目都将流回给调用者。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-03-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多