Пересоздайте 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();
}
Другие вопросы по тегам