我尝试开发类似dropbox(非常基本的)。要下载一个文件,这很容易。只需使用servletoutputstream。我想要的是:当客户端问我多个文件时,我在服务器端压缩文件然后发送给用户。但是如果文件很大,则将它们压缩并发送给用户需要花费太多时间。
有没有办法在压缩时发送文件?
感谢您的帮助。
答案 0 :(得分:4)
ZIP文件的部分Java API实际上是为了提供“即时”压缩而设计的。这一切都很适合java.io API和servlet API,这意味着它甚至......很简单(不需要多线程 - 即使出于性能原因,因为通常你的CPU在ZIPping上可能比你的网络更快将发送内容)。
您要与之互动的部分是ZipOutputStream
。它是FilterOutputStream
(这意味着它被设计为包含已存在的outputstream
- 在您的情况下,它将是respone的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这样的库来重新发明轮子......)
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部分的错误。)