_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
を使用できないと先に述べたはずです。これは、サーブレットを介してアップロードされたファイルから取得されます。
また、このコードスニペットに到達する前に、ZipInputStream
でgetNextEntry()
を呼び出しました。ファイルを別のInputStream
に(上記のOutputStream
を介して)コピーしようとせず、ZipInputStream
をサードパーティのライブラリに渡すだけの場合、ライブラリはストリームであり、ストリーム内の残りのファイルを処理するなど、これ以上何もできません。
あなたのループは有効に見えます-次のコードは(それ自体で)何を返しますか?
zipStream.read(tempBuffer)
-1が返される場合は、取得する前にzipStreamが閉じられ、すべての賭けが無効になります。デバッガーを使用して、渡されたものが実際に有効であることを確認します。
GetNextEntry()を呼び出すと、値が返されますか?また、エントリ内のデータは意味がありますか(つまり、getCompressedSize()は有効な値を返しますか)?先読みのZipエントリが埋め込まれていないZipファイルを読んでいるだけの場合、ZipInputStreamは機能しません。
Zip形式に関するいくつかの役立つ情報:
Zipファイルに埋め込まれた各ファイルにはヘッダーがあります。このヘッダーには、有用な情報(ストリームの圧縮された長さ、ファイル内のオフセット、CRCなど)を含めることができます。または、基本的に「情報がストリームヘッダーにないため、確認する必要があります」というマジック値を含めることができます。 Zipポストアンブル」。
各Zipファイルには、実際のデータとともにすべてのZipエントリを含むファイルの末尾に添付されたテーブルがあります。最後のテーブルは必須であり、その中の値は正しい必要があります。対照的に、ストリームに埋め込まれた値を指定する必要はありません。
ZipFileを使用する場合は、Zipの最後にあるテーブルを読み取ります。 ZipInputStreamを使用する場合、getNextEntry()がストリームに埋め込まれたエントリを使用しようとしていると思われます。これらの値が指定されていない場合、ZipInputStreamはストリームの長さを認識しません。インフレートアルゴリズムは自己終了します(出力を完全に回復するために出力ストリームの非圧縮長を知る必要はありません)が、このリーダーのJavaバージョン)である可能性があります。この状況をうまく処理できません。
サーブレットがZipInputStreamを返すことはかなり珍しいと言えます(圧縮されたコンテンツを受信する場合は、inflatorInputStreamを受信する方がはるかに一般的です。
おそらく次のように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);
}
}
あなたは電話を逃しています
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) {
...
}
Commons ioプロジェクトの IOUtils を使用します。
IOUtils.copy(zipStream, byteArrayOutputStream);
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();
}
}
必要なエントリに到達するまで、ZipInputStreamでgetNextEntry()を呼び出します(ZipEntry.getName()などを使用します)。 getNextEntry()を呼び出すと、「カーソル」が返されるエントリの先頭に進みます。次に、ZipEntry.getSize()を使用して、zipInputStream.read()を使用して読み取る必要のあるバイト数を決定します。
ZipStreamをどのように入手したかは不明です。このように取得すると、機能するはずです。
zipStream = zipFile.getInputStream(zipEntry)
以下のコードをお試しください
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();
}
zipStreamをどのように取得したかは不明です。このように取得すると、機能するはずです。
zipStream = zipFile.getInputStream(zipEntry)
ZipFileからZipInputStreamを取得する場合は、サードパーティライブラリ用に1つのストリームを取得して使用させ、前のコードを使用して別の入力ストリームを取得できます。
入力ストリームはカーソルであることを忘れないでください。データ全体(ZipFileなど)がある場合は、その上にN個のカーソルを要求できます。
別のケースは、「GZip」入力ストリームのみがあり、zip形式のバイトストリームしかない場合です。その場合、ByteArrayOutputStreamバッファはすべて意味があります。