Пересоздайте zip-файл из другого zip-файла
Учитывая zip-файл, мне нужно заново создать его с указанным уровнем сжатия (например, без сжатия).
Я почти у цели, но получаю ошибку:
Failed: Количество ожидаемых записей в конце центрального каталога не соответствует количеству записей в центральном каталоге.
Если я сохраняю восстановленный zip-файл в Windo ws, это выглядит так, как будто он правильный (правильный размер файла, все записи существуют с правильными размерами файла), но ни один из файлов не может быть извлечен.
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()
это возвращает ~130kb
байтовый массив.
1 ответ
Zip-архив поврежден, потому что вы читаете его содержимое из MemoryStream
прежде чем это закончено. Для завершения создания архива необходимо позвонить newArchive.Dispose()
перед звонком ms.ToArray()
, В этом конкретном случае вы можете сделать это так:
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();
}