20

から単一のファイルを読み取り、java.util.zip.ZipInputStreamそれを にコピーしようとしていますjava.io.ByteArrayOutputStream(その後、 を作成して、それjava.io.ByteArrayInputStreamをサードパーティのライブラリに渡して、ストリームを閉じてしまいます。ZipInputStream閉じたくありません) .

ここにはおそらく基本的なものが欠けていますが、ここでは while ループに入ることはありません。

ByteArrayOutputStream streamBuilder = new ByteArrayOutputStream();
int bytesRead;
byte[] tempBuffer = new byte[8192*2];
try {
    while ((bytesRead = zipStream.read(tempBuffer)) != -1) {
        streamBuilder.write(tempBuffer, 0, bytesRead);
    }
} catch (IOException e) {
    // ...
}

ストリームをコピーできるようにするために何が欠けていますか?

編集:

ZipInputStreamこれはファイルからのものではないことを先に述べておくべきだったので、 ZipFile. サーブレットを介してアップロードされたファイルからのものです。

また、このコード スニペットに到達する前にgetNextEntry()、既に を呼び出しています。ZipInputStreamファイルを別のファイルにInputStream(OutputStream上記の方法で)コピーしようとせずZipInputStream、サード パーティのライブラリに渡すだけでは、ライブラリはストリームを閉じ、残りのファイルを処理するなど、それ以上何もできません。ストリーム。

4

10 に答える 10

8

あなたのループは有効に見えます - 次のコード (それ自体) は何を返しますか?

zipStream.read(tempBuffer)

-1 を返す場合、zipStream はそれを取得する前に閉じられ、すべての賭けはオフになります。デバッガを使用して、渡されたものが実際に有効であることを確認します。

getNextEntry() を呼び出すと、値が返されますか? また、エントリ内のデータは意味がありますか (つまり、getCompressedSize() は有効な値を返しますか)? 先読みzipエントリが埋め込まれていないZipファイルを読んでいるだけの場合、ZipInputStreamは機能しません。

Zip 形式に関する便利な情報:

zip ファイルに埋め込まれた各ファイルにはヘッダーがあります。このヘッダーには、有用な情報 (圧縮されたストリームの長さ、ファイル内のオフセット、CRC など) を含めることができます。または、基本的に「情報はストリーム ヘッダーにないため、チェックする必要がある」という魔法の値を含めることもできます。 Zipポストアンブル」。

各 zip ファイルには、実際のデータとともに、すべての zip エントリを含むファイルの末尾に添付されたテーブルがあります。最後の表は必須であり、その中の値は正しい必要があります。対照的に、ストリームに埋め込まれた値は提供する必要はありません。

ZipFile を使用すると、zip の末尾にあるテーブルが読み取られます。ZipInputStream を使用している場合、getNextEntry() がストリームに埋め込まれたエントリを使用しようとしていると思われます。これらの値が指定されていない場合、ZipInputStream はストリームの長さを認識できません。inflate アルゴリズムは自己終了します (出力を完全に復元するために、出力ストリームの圧縮されていない長さを実際に知る必要はありません) が、このリーダーの Java バージョンがこの状況をうまく処理できない可能性があります。

サーブレットが ZipInputStream を返すことはかなり珍しいことです (圧縮されたコンテンツを受け取る場合は、inflatorInputStream を受け取る方がはるかに一般的です。

于 2008-09-16T04:54:35.400 に答える
7

あなたはおそらくこのようなものから読んでみましたFileInputStream

ZipInputStream in = new ZipInputStream(new FileInputStream(...));

zipアーカイブには複数のファイルが含まれている可能性があり、読み取るファイルを指定する必要があるため、これは機能しません。

java.util.zip.ZipFileと、 Apache Commons IOのIOUtilsやGuavaのByteStreamsなどのライブラリを使用して、ストリームのコピーを支援できます。

例:

ByteArrayOutputStream out = new ByteArrayOutputStream();
try (ZipFile zipFile = new ZipFile("foo.zip")) {
    ZipEntry zipEntry = zipFile.getEntry("fileInTheZip.txt");

    try (InputStream in = zipFile.getInputStream(zipEntry)) {
        IOUtils.copy(in, out);
    }
}
于 2008-09-15T22:47:11.380 に答える
4

電話がありません

ZipEntryエントリ=(ZipEntry)zipStream.getNextEntry();

最初のエントリの解凍された最初のバイトを配置します。

 ByteArrayOutputStream streamBuilder = new ByteArrayOutputStream();
 int bytesRead;
 byte[] tempBuffer = new byte[8192*2];
 ZipEntry entry = (ZipEntry) zipStream.getNextEntry();
 try {
     while ( (bytesRead = zipStream.read(tempBuffer)) != -1 ){
        streamBuilder.write(tempBuffer, 0, bytesRead);
     }
 } catch (IOException e) {
      ...
 }
于 2012-04-03T18:44:01.020 に答える
4

commons io プロジェクトのIOUtilsを使用します。

IOUtils.copy(zipStream, byteArrayOutputStream);
于 2008-09-15T21:56:02.283 に答える
3

close() を無視する ZipInputStream の周りに独自のラッパーを実装し、それをサードパーティのライブラリに渡すことができます。

thirdPartyLib.handleZipData(new CloseIgnoringInputStream(zipStream));


class CloseIgnoringInputStream extends InputStream
{
    private ZipInputStream stream;

    public CloseIgnoringInputStream(ZipInputStream inStream)
    {
        stream = inStream;
    }

    public int read() throws IOException {
        return stream.read();
    }

    public void close()
    {
        //ignore
    }

    public void reallyClose() throws IOException
    {
        stream.close();
    }
}
于 2008-09-16T03:31:48.343 に答える
1

必要なエントリになるまで、ZipInputStream で getNextEntry() を呼び出します (ZipEntry.getName() などを使用します)。getNextEntry() を呼び出すと、「カーソル」が返されるエントリの先頭に進みます。次に、ZipEntry.getSize() を使用して、zipInputStream.read() を使用して読み取るバイト数を決定します。

于 2008-09-16T00:19:01.020 に答える
0

以下のコードをお試しください

private static byte[] getZipArchiveContent(File zipName) throws WorkflowServiceBusinessException {

  BufferedInputStream buffer = null;
  FileInputStream fileStream = null;
  ByteArrayOutputStream byteOut = null;
  byte data[] = new byte[BUFFER];

  try {
   try {
    fileStream = new FileInputStream(zipName);
    buffer = new BufferedInputStream(fileStream);
    byteOut = new ByteArrayOutputStream();

    int count;
    while((count = buffer.read(data, 0, BUFFER)) != -1) {
     byteOut.write(data, 0, count);
    }
   } catch(Exception e) {
    throw new WorkflowServiceBusinessException(e.getMessage(), e);
   } finally {
    if(null != fileStream) {
     fileStream.close();
    }
    if(null != buffer) {
     buffer.close();
    }
    if(null != byteOut) {
     byteOut.close();
    }
   }
  } catch(Exception e) {
   throw new WorkflowServiceBusinessException(e.getMessage(), e);
  }
  return byteOut.toByteArray();

 }
于 2010-01-19T11:49:11.417 に答える
0

zipStreamをどのように入手したかは不明です。次のように取得すると機能するはずです。

  zipStream = zipFile.getInputStream(zipEntry)

ZipFileからZipInputStreamを取得する場合は、サードパーティライブラリ用に1つのストリームを取得して使用させ、前のコードを使用して別の入力ストリームを取得できます。

inputstreamはカーソルであることを忘れないでください。データ全体(ZipFileなど)がある場合は、その上にN個のカーソルを要求できます。

別のケースは、「GZip」入力ストリームのみがあり、zip形式のバイトストリームしかない場合です。その場合、ByteArrayOutputStreamバッファはすべて意味があります。

于 2008-09-15T22:56:16.260 に答える
0

どうやって zipStream を入手したかは不明です。次のように取得すると動作するはずです。

  zipStream = zipFile.getInputStream(zipEntry)
于 2008-09-15T21:53:13.553 に答える
-1

入力ストリームがベギングに配置されているかどうかを確認します。

それ以外の場合、実装として: 別のスレッドでこの正確なストリームを処理しない限り、読み取り中に結果ストリームに書き込む必要はないと思います。

バイト配列を作成し、入力ストリームを読み取り、出力ストリームを作成するだけです。

于 2008-09-15T21:51:43.357 に答える