名前はまだない。

プログラミングのことや趣味のことに関して綴ります。

CSVに出力したファイルをZIPに固めてDLした

今やってる仕事のなかで、はじめて取り組んだ知見があったのでまとめたいと思います。
Javaのサーバサイドフレームワーク「Spring」において、CSVファイルをZIP形式に圧縮してダウンロードしていきます。

CSVファイル作成

対象ファイル(今回はCSVファイル)を作成します。

// 対象データ作成
List<String> names= Arrays.asList("koba", "ayana", "suzuko");

// CSVファイルリスト生成
List<File> files = names.stream()
        .map(name -> {
            // ファイル作成
            File file = new File(fileName + ".csv");

            try (PrintWriter pw = new PrintWriter(new BufferdWriter(
                    new OutputStreamWriter(new FileOutputStream(file), "shift_jis")))) {
                pw.print(name);
                pw.print(",");
                pw.print("\r\n"); // Windowsの改行コード(CR+LF)
            }
        })
        .collect(Collectors.toList());
日本語文字化け

ここで問題になったのが、ファイルに出力される値およびファイル名が日本語の場合、文字化けしてしまうというもの。
標準のAPIではZIP形式のファイル名のエンコードを変更することができません。
なので、ここではorg.apache.tools.zipのZipOutputStreamを使用していきます。
こいつはエンコードをセットすることが出来るので日本語対応もバッチリ出来るはずです!

Mavenの依存関係にantを追記

<!-- apache-ant -->
<dependency>
    <groupId>org.apache.ant</groupId>
    <artifactId>ant</artifactId>
    <version>1.7.1</version>
</dependency>

ZIPに圧縮

対象ファイルをZIP形式に圧縮します(ここが肝です)

import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipOutputStream;

// 中略

@RequestMapping(value = "/hogehoge/download", method = { RequestMethod.GET })
public void download(HttpServletResponse response) {
    try (ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()))) {
        // エンコードをセット(大事)
        zos.setEncoding("shift_jis");
        files.forEach(file -> {
            try (InputStream in = new BufferedInputStream(new FileInputStream(f))) {
                // CSVファイルをzip形式に圧縮するためにセット
                zos.putNextEntry(new ZipEntry(f.getName));

                byte[] b = new byte[1024];
                int len;
                while ((len = in.read(b)) != -1) {
                    // zip形式で書き込む
                    zos.write(b, 0, len);
                }
                zos.closeEntry();
            }
        });
    }
}

ファイルをDLする!

responseのヘッダーに値をセットしましょう。

// レスポンスに値をセット
responce.setContentType("application/octet-stream;charset=shift_jis");
responce.setHeader("Content-Disposition", "attachment; filename=" +  URLEncoder.encode(fileNamePrefix + ".zip", "UTF-8"));
responce.setHeader("Content-Transfer-Encoding", "binary");

参考サイト

tanakakns.hatenablog.com

http://nvtrlab.jp/blog/penco/org-apache-tools-zip.html