从另一个 zip 文件重新创建 zip 文件
Re-create zip file from another zip file
给定一个 zip 文件,我需要使用指定的压缩级别(例如,不压缩)重新创建它。
我快到了,但出现错误:
Failed: Number of entries expected in End Of Central Directory does not correspond to number of entries in Central Directory.
如果我将重新创建的 zip 文件保存到 windows,它看起来是正确的(正确的文件大小,所有条目都以正确的文件大小存在)但是 none 个文件是可提取的。
public static byte[] ReCompress(byte[] originalArchive, CompressionLevel newCompressionLevel)
{
var entries = new Dictionary<string, byte[]>();
///////////////////////////
// STEP 1: EXTRACT ALL FILES
///////////////////////////
using (var ms = new MemoryStream(originalArchive))
using (var originalZip = new ZipArchive(ms, ZipArchiveMode.Read))
{
foreach (var entry in originalZip.Entries)
{
var isFolder = entry.FullName.EndsWith("/");
if (!isFolder)
{
using (var stream = entry.Open())
using (var entryMS = new MemoryStream())
{
stream.CopyTo(entryMS);
entries.Add(entry.FullName, entryMS.ToArray());
}
}
else
{
entries.Add(entry.FullName, new byte[0]);
}
}
}
///////////////////////////
// STEP 2: BUILD ZIP FILE
///////////////////////////
using (var ms = new MemoryStream())
using (var newArchive = new ZipArchive(ms, ZipArchiveMode.Create, true))
{
foreach (var uncompressedEntry in entries)
{
var newEntry = newArchive.CreateEntry(uncompressedEntry.Key, newCompressionLevel);
using (var entryStream = newEntry.Open())
using (var writer = new BinaryWriter(entryStream, Encoding.UTF8))
{
writer.Write(uncompressedEntry.Value);
}
}
return ms.ToArray();
}
}
在函数的末尾,如果我这样做:
File.WriteAllBytes(@"D:\test.zip", ms.ToArray());
它创建了一个结构正确的压缩文件,大小为 90mb
,但没有文件是可提取的。
如果我以 return ms.ToArray()
结尾,它 returns 一个 ~130kb
字节数组。
Zip 存档已损坏,因为您在完成之前从 MemoryStream
读取了它的内容。为了完成存档创建,您需要在调用 ms.ToArray()
之前调用 newArchive.Dispose()
。
在这种特殊情况下,您可以这样做:
using (var ms = new MemoryStream())
{
using (var newArchive = new ZipArchive(ms, ZipArchiveMode.Create, true))
{
foreach (var uncompressedEntry in entries)
{
var newEntry = newArchive.CreateEntry(uncompressedEntry.Key, newCompressionLevel);
using (var entryStream = newEntry.Open())
using (var writer = new BinaryWriter(entryStream, Encoding.UTF8))
{
writer.Write(uncompressedEntry.Value);
}
}
}
return ms.ToArray();
}
给定一个 zip 文件,我需要使用指定的压缩级别(例如,不压缩)重新创建它。
我快到了,但出现错误:
Failed: Number of entries expected in End Of Central Directory does not correspond to number of entries in Central Directory.
如果我将重新创建的 zip 文件保存到 windows,它看起来是正确的(正确的文件大小,所有条目都以正确的文件大小存在)但是 none 个文件是可提取的。
public static byte[] ReCompress(byte[] originalArchive, CompressionLevel newCompressionLevel)
{
var entries = new Dictionary<string, byte[]>();
///////////////////////////
// STEP 1: EXTRACT ALL FILES
///////////////////////////
using (var ms = new MemoryStream(originalArchive))
using (var originalZip = new ZipArchive(ms, ZipArchiveMode.Read))
{
foreach (var entry in originalZip.Entries)
{
var isFolder = entry.FullName.EndsWith("/");
if (!isFolder)
{
using (var stream = entry.Open())
using (var entryMS = new MemoryStream())
{
stream.CopyTo(entryMS);
entries.Add(entry.FullName, entryMS.ToArray());
}
}
else
{
entries.Add(entry.FullName, new byte[0]);
}
}
}
///////////////////////////
// STEP 2: BUILD ZIP FILE
///////////////////////////
using (var ms = new MemoryStream())
using (var newArchive = new ZipArchive(ms, ZipArchiveMode.Create, true))
{
foreach (var uncompressedEntry in entries)
{
var newEntry = newArchive.CreateEntry(uncompressedEntry.Key, newCompressionLevel);
using (var entryStream = newEntry.Open())
using (var writer = new BinaryWriter(entryStream, Encoding.UTF8))
{
writer.Write(uncompressedEntry.Value);
}
}
return ms.ToArray();
}
}
在函数的末尾,如果我这样做:
File.WriteAllBytes(@"D:\test.zip", ms.ToArray());
它创建了一个结构正确的压缩文件,大小为 90mb
,但没有文件是可提取的。
如果我以 return ms.ToArray()
结尾,它 returns 一个 ~130kb
字节数组。
Zip 存档已损坏,因为您在完成之前从 MemoryStream
读取了它的内容。为了完成存档创建,您需要在调用 ms.ToArray()
之前调用 newArchive.Dispose()
。
在这种特殊情况下,您可以这样做:
using (var ms = new MemoryStream())
{
using (var newArchive = new ZipArchive(ms, ZipArchiveMode.Create, true))
{
foreach (var uncompressedEntry in entries)
{
var newEntry = newArchive.CreateEntry(uncompressedEntry.Key, newCompressionLevel);
using (var entryStream = newEntry.Open())
using (var writer = new BinaryWriter(entryStream, Encoding.UTF8))
{
writer.Write(uncompressedEntry.Value);
}
}
}
return ms.ToArray();
}