web-dev-qa-db-ja.com

ZipInputStreamからByteArrayOutputStreamへの読み取り

_Java.util.Zip.ZipInputStream_から1つのファイルを読み取り、それを_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を使用できないと先に述べたはずです。これは、サーブレットを介してアップロードされたファイルから取得されます。

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

17
pkaeding

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

zipStream.read(tempBuffer)

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

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

Zip形式に関するいくつかの役立つ情報:

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

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

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

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

7
Kevin Day

おそらく次のように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);
    }
}
7

あなたは電話を逃しています

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) {
      ...
 }
4
Juan Ignacio

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

IOUtils.copy(zipStream, byteArrayOutputStream);
4
ScArcher2

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();
    }
}
3
jt.

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

1
Boris Bokowski

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

  zipStream = zipFile.getInputStream(zipEntry)
0
Boris Bokowski

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

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();

 }
0
Dmytro

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

  zipStream = zipFile.getInputStream(zipEntry)

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

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

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

0
helios