start of central directory not found;
zipfile corrupt.
アプリで、例外をスローする .zip ファイルを受信することがあります。これらの zip ファイルは、Mac の Finder で問題なく開きます。
コマンドラインから毎回これらのファイルを修正できます。zip -FF bad.zip --out good.zip
そこにあるJava ZIPライブラリは同じことを達成できますか?
厳密に言えば、zip はコンテナーに似ており、さまざまな圧縮アルゴリズムを含めることができるため、おそらく Java にこのコマンドを実行させたいと思うでしょう。
一般に、プログラムによるアプローチで圧縮アーカイブに関連する問題を調査して解決することは、トリッキーで時間のかかる作業になる可能性があります。
コマンドでこれを試してください。
ZipInputStream と ZipOutputStream を使用してみました。しかし、「getNextEntry()」を実行すると、ZipInputStream は常にどこかの時点で失敗しました。基本的に、「getNextEntry()」の次のコード行:
...
if ((entry = readLOC()) == null) {
return null;
}
...
いくつかのエントリの後に null を返し、それ以上進むことができませんでした。
しかし、ZipFile は問題なくすべての zip エントリを読み取っていたため、ZipFile を ZipOutputStream と一緒に使用して問題を解決できました。解決策は次のようになります。
protected void repairZipFile(String file) throws IOException {
File repairZipFile = new File(file+".repair");
ZipFile zipFile = new ZipFile(file);
Enumeration<? extends ZipEntry> zipFileEntries = zipFile.entries();
InputStream zis;
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(repairZipFile));
byte[] b = new byte[1024];
while(zipFileEntries.hasMoreElements()){
ZipEntry zipEntry = zipFileEntries.nextElement();
zos.putNextEntry(zipEntry);
zis = zipFile.getInputStream(zipEntry);
int n = zis.read(b);
while(n>=0) {
zos.write(b, 0, n);
n = zis.read(b);
}
zis.close();
zos.closeEntry();
}
zipFile.close();
zos.flush();
zos.close();
Files.move(repairZipFile.toPath(), (new File(file)).toPath(), StandardCopyOption.REPLACE_EXISTING);
}
Java で ZIP ファイルを開くには、ZipFileクラスを使用する方法とZipInputStreamを使用する方法の 2 つがあります。
私が覚えている限りZipFile
では、zip ファイルの中央ディレクトリを最初に読み取りRandomAccessFile
ます。ただし、ZipInputStream
インライン エントリ情報を使用します。これは、ファイルの最後に存在すると思われる中央ディレクトリが見つからないか破損している場合に適している可能性があります。
そのため、ZipInputStream を使用して ZIP ファイルを読み取り、ZipOutputStream を使用して別のファイルに書き戻し、それらの間でエントリ情報をコピーすることにより、Java で ZIP ファイルを「修復」できる可能性があります。切り捨てられた場合、ZipInputStream の最後のエントリから読み取り IO 例外が発生する可能性がありますが、ファイルから他の以前のエントリを保存する可能性があります。