【发布时间】:2014-10-10 06:08:37
【问题描述】:
我尝试开发类似 dropbox 的东西(非常基本的)。对于一个文件下载,这真的很容易。只需使用 servletoutputstream。我想要的是:当客户问我多个文件时,我在服务器端压缩文件然后发送给用户。但是如果文件很大,压缩它们并发送给用户需要太多次。
有什么方法可以在压缩的同时发送文件吗?
感谢您的帮助。
【问题讨论】:
标签: java multithreading io zip
我尝试开发类似 dropbox 的东西(非常基本的)。对于一个文件下载,这真的很容易。只需使用 servletoutputstream。我想要的是:当客户问我多个文件时,我在服务器端压缩文件然后发送给用户。但是如果文件很大,压缩它们并发送给用户需要太多次。
有什么方法可以在压缩的同时发送文件吗?
感谢您的帮助。
【问题讨论】:
标签: java multithreading io zip
ZIP 文件的部分 Java API 实际上旨在提供“动态”压缩。这一切都非常适合 java.io API 和 servlet API,这意味着这甚至......有点简单(不需要多线程 - 即使出于性能原因,因为通常你的 CPU 在 ZIPping 时可能会比你的网络更快将在发送内容时)。
您将与之交互的部分是ZipOutputStream。它是一个FilterOutputStream(这意味着它旨在包装一个已经存在的outputstream - 在您的情况下,这将是响应的OutputStream),并将使用ZIP压缩压缩您发送它的每个字节。
所以,假设你有一个获取请求
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// Your code to handle the request
List<YourFileObject> responseFiles = ... // Whatever you need to do
// We declare that the response will contain raw bytes
response.setContentType("application/octet-stream");
// We open a ZIP output stream
try (ZipOutputStream zipStream = new ZipOutputStream(response.getOutputStream()) {// This is Java 7, but not that different from java 6
// We need to loop over each files you want to send
for(YourFileObject fileToSend : responseFiles) {
// We give a name to the file
zipStream.putNextEntry(new ZipEntry(fileToSend.getName()));
// and we copy its content
copy(fileToSend, zipStream);
}
}
}
当然,您应该进行适当的异常处理。不过有几个快速说明:
IllegalStateException)putNextEntry 时,它都会自行关闭前一个(如果需要)ZipOutputStream,它就会关闭它。copy 方法正是您用来将所有字节从原始文件传输到输出流的方法,它没有特定的ZIP。只需致电outputStream.write(byte[] bytes)。**编辑:**澄清......
例如,给定一个YourFileType,它具有以下方法:
public interface YourFileType {
public byte[] getContent();
public InputStream getContentAsStream();
}
然后复制方法可能看起来像(这都是非常基本的 Java IO,您可以使用诸如 commons io 之类的库来避免重新发明轮子...)
public void copy(YourFileType file, OutputStream os) throws IOException {
os.write(file.getContent());
}
或者,对于完整的流式实现:
public void copy(YourFileType file, OutputStream os) throws IOException {
try (InputStream fileContent = file.getContentAsStream()) {
byte[] buffer = new byte[4096]; // 4096 is kind of a magic number
int readBytesCount = 0;
while((readBytesCount = fileContent.read(buffer)) >= 0) {
os.write(buffer, 0, readBytesCount);
}
}
}
使用这种实现,您的客户端几乎会在您开始写入ZIPOutputStream 时开始收到响应(唯一的延迟是内部缓冲区的延迟),这意味着它不应该超时(除非您也花费了长时间构建要发送的内容 - 但这不是 ZIPping 部分的错误)。
【讨论】: