5

含まれている各ファイルがいくつかのオブジェクトをシリアル化することによって生成される Java で zip アーカイブを作成したいと考えています。ストリームを正しく閉じるのに問題があります。

コードは次のようになります。

try (OutputStream os = new FileOutputStream(file);
     ZipOutputStream zos = new ZipOutputStream(os);) {

  ZipEntry ze;
  ObjectOutputStream oos;

  ze = new ZipEntry("file1");
  zos.putNextEntry(ze); // start first file in zip archive
  oos = new ObjectOutputStream(zos);
  oos.writeObject(obj1a);
  oos.writeObject(obj1b);
  // I want to close oos here without closing zos
  zos.closeEntry(); // end first file in zip archive

  ze = new ZipEntry("file2");
  zos.putNextEntry(ze); // start second file in zip archive
  oos = new ObjectOutputStream(zos);
  oos.writeObject(obj2a);
  oos.writeObject(obj2b);
  // And here again
  zos.closeEntry(); // end second file in zip archive
}

もちろん、使い終わったら各ストリームを閉じる必要があることはわかっているのでObjectOutputStream、指定された位置で s を閉じる必要があります。ただし、 を閉じると、まだ必要なObjectOutputStreamも閉じます。ZipOutputStream

への呼び出しを省略したくありません。なぜなら、現在はand をObjectOutputStream.close()超えていないという事実に依存したくないからです。flush()reset()

また、単一のObjectOutputStreamインスタンスを使用することもできません。これは、コンストラクターによって書き込まれたストリーム ヘッダーを見逃すためです (zip アーカイブ内の各ファイルは完全なオブジェクトのシリアル化ファイルではなく、個別に逆シリアル化できませんでした)。

ファイルを再度読み込むと、同じ問題が発生します。

私が見る唯一の方法は、に渡す前をZipOutputStream除いてすべてのメソッドを転送するある種の「CloseProtectionOutputStream」でラップすることです。しかし、これはかなりハッキリしているようで、API でより優れたソリューションを見逃していたのではないかと思います。close()ObjectOutputStream

4

3 に答える 3

2

とにかく ObjectOutputStream を捨てるつもりなら、flush()ではなく呼び出すだけで十分なはずclose()ですが、質問で言うように、最も安全な方法は、呼び出しをブロックする基礎となる ZipOutputStream の周りにラッパーを使用することclose()です。Apache commons-io には、この目的のためにCloseShieldOutputStreamがあります。

于 2013-04-10T12:35:21.267 に答える
2

この場合、あなたが言及したすべての理由から、私は単純に myObjectOutputStreamを にパイプしませんZipOutputStream。代わりに、 にシリアライズしてから、byte[]それを に直接書き込みZipOutputStreamます。このようにして、を自由に閉じることができ、生成するObjectOutputStreamそれぞれbyte[]にシリアライザーからの適切なヘッダーが含まれます。欠点の 1 つは、byte[]以前にはなかったインメモリができてしまうことですが、数百万のオブジェクトについて話しているのでなければ、ガベージ コレクタがクリーニングに苦労することはないはずです。上。

ちょうど私の2セント...

少なくとも、動作を変更するストリーム サブクラスよりもハッキリしていないように思えclose()ます。

于 2013-04-10T12:07:43.180 に答える