2010-08-17 187 views
0

我想創建一個使用servlets的zip文件,但它會返回一個損壞的zip文件,這是zipcontents函數中的代碼,我正在創建zip文件,有人可以幫助我出去了。提前致謝。下載壓縮文件返回使用servlets損壞的zip

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

回答

2

代碼中存在太多問題。其中主要的是:

  1. zos被聲明爲servlet實例變量。這是非線程安全。它已被多個請求共享。如果子請求未完成,您可能會覆蓋前一個請求。

  2. 通過bout.toString()將二進制ZIP內容轉換爲字符數據。這肯定會破壞二進制數據。您應該使用通常的InputStream#read()/OutputStream#write()循環將二進制數據寫爲二進制數據。

  3. 該代碼在每個條目結束時不會調用zos.closeEntry()

我認爲#2是主要原因。您不需要ByteArrayOutputStream。這只是一個不必要的記憶豬。只需將response.getOutputStream()包裝在ZipOutputStream中即可。

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

非常感謝它解決了這個問題。 – Vinay 2010-08-18 04:46:52

+0

不客氣。 – BalusC 2010-08-18 11:09:05

0

另一個可能的原因是編譯servlet的應用程序服務器和編譯器的不同JVM版本。 非常罕見的問題,但veeery難以理解。

0

您可以像這樣創建 ZipOutputStream zipOut = new ZipOutputStream(res. getOutputStream()); 並且您寫入zip條目的每個zip條目都將被傳回給調用者。