はじめに
* ファイルを圧縮して、そのファイルをダウンロードするといった場合、 以下のようなことになる 1) 一次ファイルを作成しなければならない(そして、そのファイルを消さなければならない) 2) ZIP化する際にループし、ダウンロード時でも同じようなループするので処理が無駄
サンプル
import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet implementation class ZipDownloadServlet */ public class SampleZipDownloadControl extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public SampleZipDownloadControl() { super(); } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.downloadZipFile( response, "Sample.zip", "C:\\temp\\Sample1", "C:\\temp\\Sample2", "C:\\temp\\Sample1.txt", "C:\\temp\\Sample2.txt"); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } private void downloadZipFile(HttpServletResponse response, String outputZipFileName, String... inputFilePathes) throws ServletException { try (ServletOutputStream outputStream = response.getOutputStream(); ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);) { response.setContentType("application/zip"); response.setHeader("Content-Disposition", String.format("attachment; filename=\"%s\"", outputZipFileName)); for (String inputFilePath : inputFilePathes) { File file = new File(inputFilePath); this.zip(zipOutputStream, file, file); } } catch (Exception ex) { ex.printStackTrace(); throw new ServletException("Download failed...", ex); } } private void zip(ZipOutputStream zipOutputStream, File rootFile, File targetFile) { if (targetFile.isDirectory()) { // Directory File[] files = targetFile.listFiles(); for (File file : files) { this.zip(zipOutputStream, rootFile, file); } } else { // File String zipEntryPath = this.getZipEntryPath(rootFile, targetFile); ZipEntry zipEntry = new ZipEntry(zipEntryPath); try (BufferedInputStream inputStream = new BufferedInputStream( new FileInputStream(targetFile))) { zipOutputStream.putNextEntry(zipEntry); this.writeStream(inputStream, zipOutputStream); zipOutputStream.closeEntry(); } catch (FileNotFoundException ex) { ex.printStackTrace(); } catch (IOException ex) { ex.printStackTrace(); } } } private String getZipEntryPath(File rootFile, File targetFile) { int lengthToExtractZipPath = rootFile.getPath().length() - rootFile.getName().length(); return targetFile.getPath().replace("\\\\", "/") .substring(lengthToExtractZipPath); } private void writeStream(InputStream inputStream, OutputStream outputStream) throws IOException { int availableByteNumber; while ((availableByteNumber = inputStream.available()) > 0) { byte[] buffers = new byte[availableByteNumber]; int readByteNumber = inputStream.read(buffers); if (readByteNumber < 0) { break; } outputStream.write(buffers, 0, readByteNumber); } } }
動作補足
* 以下にも対応。 1) フォルダが入れ子 2) 複数フォルダを指定してZip化する
問題
1) Windows7において、日本語のファイル名が文字化けする ※ Windows8.1だと起こらない。
解決法
* Apache のツールを使うhttp://symfoware.blog68.fc2.com/blog-entry-724.html
http://www.saka-en.com/java/java-zip-compress/