はじめに
そのままでサイズ大きいファイルを、gzip圧縮したままでやりとりするケースがあります。
javaでのgzipでのファイルの読み書きを整理しました。Java8のときからのものですが、java11でもいけそうです。
読み込み
csvファイルをgzip圧縮したものを例にします
ポイントは
- try-with-resources構文を使う
- InputSreamをGZIPInputStreamでラップする
- GZIPInputStreamをInputStreamReaderでラップする
- InputStreamReaderのときに、エンコーディングを指定できる
- InputStreamReaderをBufferedReaderでラップする
Java
Path path = Paths.get("read_test.csv.gz");
try(
InputStream is = Files.newInputStream(path);
GZIPInputStream gis = new GZIPInputStream(is);
InputStreamReader isReader = new InputStreamReader(gis, StandardCharsets.UTF_8);
BufferedReader br = new BufferedReader(isReader);
) {
br.lines().forEach(System.out::println);
}
BufferedReaderでラップするのは性能のためです。
実践では、csv読み込みのライブラリを使うのが通例ですね。
ここではunivocity_parsers を使ったサンプルをあげてみます。
大容量を想定して、iteratorで取り扱う例です。
Path path = Paths.get("read_test.csv.gz");
try(
InputStream is = Files.newInputStream(path);
GZIPInputStream gis = new GZIPInputStream(is);
InputStreamReader isReader = new InputStreamReader(gis, StandardCharsets.UTF_8);
BufferedReader br = new BufferedReader(isReader);
) {
CsvParserSettings parserSettings = new CsvParserSettings();
CsvRoutines routines = new CsvRoutines(parserSettings);
Iterator<TestDTO> iterator = routines.iterate(TestDTO.class, br).iterator();
iterator.forEachRemaining(x -> System.out.println(x.toString()));
}
書き込み
ポイントは読み込みとほぼ同様で
- try-with-resources構文を使う
- OutputStreamをGZIPOutputStreamでラップする
- GZIPOutputStreamをOutputStreamWriterでラップする
- OutputStreamWriterでエンコーディングを指定できる
- OutputStreamWriterをBufferedWriterでラップする
Path path = Paths.get("write_test.csv.gz");
try (
OutputStream os = Files.newOutputStream(path,StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE);
GZIPOutputStream gzip = new GZIPOutputStream(os);
OutputStreamWriter ow = new OutputStreamWriter(gzip, StandardCharsets.UTF_8);
BufferedWriter bw = new BufferedWriter(ow);) {
List<String> rows = ...;
rows.stream().forEach(row -> bw.write(row));
}
csvライブラリを使っての書き込みの例はこうなります。
Path path = Paths.get("write_test.csv.gz");
try (
OutputStream os = Files.newOutputStream(path,StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE);
GZIPOutputStream gzip = new GZIPOutputStream(os);
OutputStreamWriter ow = new OutputStreamWriter(gzip, StandardCharsets.UTF_8);
BufferedWriter bw = new BufferedWriter(ow);) {
List<TestDTO> rows = ...;
CsvWriterSettings writerSettings = new CsvWriterSettings();
CsvWriter writer = new CsvWriter(bw , writerSettings);
rows.stream().forEach(rows -> writer.processRecord(row));
}
所感
やり方がわかればなんてことはないですが、一体、何回オブジェクトをラップすればいいんだ、という感じです。基本的に、csvライブラリにはreader or writerを渡せば、よしなにやってくれることが多いです。その点では、何度もラップした甲斐があるというものです。
参考リンク
- https://qiita.com/neko_the_shadow/items/dd4ce3f71388771c2bb7
- https://www.journaldev.com/966/java-gzip-example-compress-decompress-file
- http://commons.apache.org/proper/commons-compress/examples.html
- https://qiita.com/wakwak/items/49d5ffdb8372f45f4289
- https://docs.oracle.com/javase/jp/8/docs/api/java/io/BufferedReader.html
- https://qiita.com/ksby/items/f5b2f0f04e2ba590d270
- https://www.univocity.com/pages/univocity_parsers_tutorial.html
- https://www.univocity.com/pages/univocity_parsers_routines.html