ushumpei’s blog

生活で気になったことを随時調べて書いていきます。

GZIPOutputStream と ByteArrayOutputStream と try with resources

Javatry with resources は途中で return してもリソースの close をしてくれるけど、なんか間違えた。

GZIPOutputStreamByteArrayOutputStream を使って以下のような、データを圧縮してバイト列にして返す処理を書いていました。( InputStream の部分は実際は外部のファイルのストリームとかになると思います)

String input = "hogehogehoge";
InputStream in = new ByteArrayInputStream(input.getBytes());

try (
  BufferedReader reader = new BufferedReader(new InputStreamReader(in));
  ByteArrayOutputStream out = new ByteArrayOutputStream();
  BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new GZIPOutputStream(out)))
) {

  String line;
  while ((line = reader.readLine()) != null) {
    writer.write(line);
    writer.newLine();
  }

  return out.toByteArray();

} catch (IOException e) {
  e.printStackTrace();
  throw new RuntimeException(e);
}

すると次の例外が発生。

java.io.EOFException: Unexpected end of ZLIB input stream

これは GZIPOutputStream を閉じていないときに出る例外で、「 try with resources だから閉じられるのでは?」と思いましたが、 toByteArray しているタイミングはまだ処理が try を抜けていないので閉じられていなかったようです。

以下のように変更して解決しました。バイト列を取得するのは try を抜けてから行うようにしました。

String input = "hogehogehoge";
InputStream in = new ByteArrayInputStream(input.getBytes());

ByteArrayOutputStream out = new ByteArrayOutputStream();

try (
  BufferedReader reader = new BufferedReader(new InputStreamReader(in));
  BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new GZIPOutputStream(out)))
) {

  String line;
  while ((line = reader.readLine()) != null) {
    writer.write(line);
    writer.newLine();
  }

} catch (IOException e) {
  e.printStackTrace();
  throw new RuntimeException(e);
}
return out.toByteArray();

感想

すぐ終わると思って書いたコードが動かなくて夜が明けてしまった。

最近景気が悪いので、仕事がなくなったら各地のお祭りを巡る旅とかしたい。