使用 servlet 下载 zip 文件会返回损坏的 zip

发布于 2024-09-14 21:05:53 字数 2407 浏览 6 评论 0原文

我正在尝试使用 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();
    }
}

I am trying to create a zip file using servlets but it returns me a corrupt zip file , here is the code for that in zipcontents function i am creating the zip , can someone help me out. Thanks in Advance.

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

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

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

发布评论

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

评论(3

燕归巢 2024-09-21 21:05:53

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

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

There are too much problems in the code. the major ones which springs in are:

  1. The zos is been declared as servlet instance variable. This is not threadsafe. It is been shared among multiple requests. You risk that a subseuent request overwrites the previous one when it's not been finished.

  2. The binary ZIP content is been converted to character data with bout.toString(). This will definitely corrupt binary data. You should write binary data as binary data using the usual InputStream#read()/OutputStream#write() loop.

  3. The code does not call zos.closeEntry() at end of each entry.

I think #2 is the major cause. You don't need ByteArrayOutputStream. It's only an unnecessary memory hog. Just wrap the response.getOutputStream() in ZipOutputStream.

ZipOutputStream output = new ZipOutputStream(response.getOutputStream());
zipFiles(directory.listFiles(), output);
output.close();
亣腦蒛氧 2024-09-21 21:05:53

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

One more possible reason is different JVM versions of application server and compiler which compiles servlet.
Very rare issue but veeery hard to understand.

﹏半生如梦愿梦如真 2024-09-21 21:05:53

你可以像这样创建
ZipOutputStream zipOut = new ZipOutputStream(res.getOutputStream());
您写入 zip 条目的每个 zip 条目都将流式传输回调用者。

You could create like this
ZipOutputStream zipOut = new ZipOutputStream(res. getOutputStream());
And every zip entry you write into zip entry will be streamed back to the caller.

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