![](/img/trans.png)
[英]Using a servlet, how do you download multiple files from a database and zip them for client download
[英]Servlet - how to download multiples files from database
我環顧四周,似乎將所有文件壓縮在一起就是要走的路。 如果是這種情況,這就是我想要做的設計。 如果有更有效的方法,請告訴我
我可以創建BufferedOutputStream並將blob寫入不同的文件,我想在完成之后,我可以壓縮文件。 (這是拉鏈所有文件的好方法還是有更好更快的方法來實現這個?)完成拉鏈后,然后發送給客戶端(不知道怎么做,請任何人都知道如何,請幫助)請指出我的設計是否有任何缺陷。 我在上面發布了一些問題,並且真的很感激,任何人都可以幫我回答。 示例代碼非常棒。 非常感謝你,祝你新年快樂
基本上你只需要在response.getOutputStream()
周圍構建一個新的ZipOutputStream
,然后將每個InputStream
從DB添加為新的ZipEntry
。 為了提高性能,可以包住response.getOutputStream()
中BufferedOutputStream
預先和所述InputStream
在BufferedInputStream
並使用byte[]
緩沖液中。
這是一個基本的例子:
package com.example;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ZipFileServlet extends HttpServlet {
private static final int DEFAULT_BUFFER_SIZE = 10240; // 10KB.
private YourFileDAO yourFileDAO = YourDAOFactory.getYourFileDAO();
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String[] fileIds = request.getParameterValues("fileId");
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename=\"allfiles.zip\"");
ZipOutputStream output = null;
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
try {
output = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE));
for (String fileId : fileIds) {
YourFileItem item = yourFileDAO.find(fileId);
if (item == null) continue; // Handle yourself. The fileId may be wrong/spoofed.
InputStream input = null;
try {
input = new BufferedInputStream(item.getInputStream(), DEFAULT_BUFFER_SIZE);
output.putNextEntry(new ZipEntry(item.getName()));
for (int length = 0; (length = input.read(buffer)) > 0;) {
output.write(buffer, 0, length);
}
output.closeEntry();
} finally {
if (input != null) try { input.close(); } catch (IOException logOrIgnore) { /**/ }
}
}
} finally {
if (output != null) try { output.close(); } catch (IOException logOrIgnore) { /**/ }
}
}
}
可以通過以下形式調用:
<form action="zipFile" method="post">
<input type="checkbox" name="fileId" value="1"> foo.exe<br>
<input type="checkbox" name="fileId" value="2"> bar.pdf<br>
<input type="checkbox" name="fileId" value="3"> waa.doc<br>
<input type="checkbox" name="fileId" value="4"> baz.html<br>
<input type="submit" value="download zip">
</form>
這就是說,做到不以任何方式使用ByteArrayInputStream/ByteArrayOutputStream
一些這里可能建議。 那些是由原始byte[]
。 當bytearrays中的所有文件(來自所有並發用戶!)的大小大於可用服務器內存時,您可能會冒應用程序中斷的風險。 您已有來自數據庫的流和響應的流。 只需將它們通過讀/寫循環中的小字節緩沖區進行管道傳輸即可。 您不需要在(引擎蓋下)大量字節緩沖區中獲取整個輸入流,然后將其寫入輸出流。
您不應該首先編寫文件。 您可以創建一個zip文件。
FileOutputStream fos = new FileOutputStream(zipFileName);
zipOutStream = new ZipOutputStream(fos);
然后,您可以為從數據庫中讀取的每個文件添加條目
ZipEntry zipEntry = new ZipEntry("NameOfFileToBeAdded");
zipOutStream.putNextEntry(zipEntry);
zipOutStream.write(byteArrayOfFileEntryData);
zipOutStream.closeEntry();
當然,寫入可以在循環中完成,因此byteArrayOfFileEntryData不會耗盡所有服務器內存。
添加完所有zip條目后,請關閉zip文件
zipOutStream.close();
創建zip文件后,您仍然需要將其返回給用戶。
編輯:一個選項是創建包裝響應輸出流的zip文件輸出流。 這樣,zip文件也不需要存儲在服務器上。 我沒有測試過這個選項。
zipOutStream = new ZipOutputStream(response.getOutputStream())
我們在單獨的機器上構建zip文件,該機器具有自己的Tomcat服務器以返回zip文件。 向用戶顯示一個“等待”頁面,顯示他們選擇的文件列表,這些文件會在壓縮所有文件后自動刷新以顯示zip文件的鏈接。 這樣,一旦用戶看到zip文件的大小,就可以重新考慮下載。 它還將zip文件保留在主應用程序服務器之外。
您不需要將數據庫blob寫入臨時文件,因為您可以在servlet中動態創建zip文件。 這包括完整的zip文件和所有條目。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.