【问题标题】:ZipArchive does not properly compress files with MemoryStreamZipArchive 无法使用 MemoryStream 正确压缩文件
【发布时间】:2015-03-17 09:08:49
【问题描述】:

我正在使用 .NET 4.5 的 ZipArchive,它与 FileStream 一起正常工作:

public static byte[] CompressWithFiles(string dir)
{
    var archiveName = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString() + ".zip");    
    var files = Directory.GetFiles(testsConsoleDir);
    using (var stream = new FileStream(archiveName, FileMode.Create))
    {
        using (var archive = new ZipArchive(stream, ZipArchiveMode.Create))
        {
            foreach (var file in files)
                archive.CreateEntryFromFile(file, Path.GetFileName(file), CompressionLevel.Optimal);
        }
    }
    byte[] result = File.ReadAllBytes(archiveName);

    return result;
}

但是,如果我尝试使用 MemoryStream 压缩文件,它会返回无法打开的字节数组并保存到磁盘:

public static byte[] CompressInMemory(string dir)
{
    var files = Directory.GetFiles(dir);
    byte[] result = null;
    using (var stream = new MemoryStream())
    {
        using (var archive = new ZipArchive(stream, ZipArchiveMode.Create))
        {
            foreach (var file in files)
                archive.CreateEntryFromFile(file, Path.GetFileName(file), CompressionLevel.Optimal);

            stream.Position = 0;
            result = new byte[stream.Length];
            stream.Read(result, 0, (int)stream.Length);
        }
    }

    return result;
}

我比较了第一种方法和第二种方法的数组,发现它们是相等的,除了第一个数组末尾有一个剩余字节,这使得 zip 存档可以打开。如何在CompressInMemory 方法中解决此问题?我试图避免将数据存储在磁盘上。

【问题讨论】:

    标签: .net compression zip


    【解决方案1】:

    您必须在阅读之前“关闭”压缩包:

    using (var archive = new ZipArchive(stream, ZipArchiveMode.Create, true))
    {
        foreach (var file in files)
            archive.CreateEntryFromFile(file, Path.GetFileName(file), CompressionLevel.Optimal);
    }
    
    stream.Position = 0;
    result = new byte[stream.Length];
    stream.Read(result, 0, (int)stream.Length);        
    
    // Note that you can replace the previous 3 rows
    // from stream.Position = 0 onward) with:
    //result = stream.ToArray();
    

    但您必须将ZipArchive 设置为在关闭时将流“未处理”(最终的true)。

    通过这种方式,zip 被“刷新”到流中。如果您注意到您在FileStream 示例中正确执行了此操作。

    一般情况下,您应该在stream.Flush() 之前 执行stream.Position = 0,因为stream 可能有一些未写入的内部缓冲区,但对于MemoryStream,这不是必需的,因为@987654321 @

    重写 Stream.Flush 方法以便不执行任何操作

    【讨论】:

    • 我试过这段代码。但它会抛出一个ObjectDisposedException。添加stream.Flush() 无效。
    • @KvanTTT 已测试。添加true 作为new ZipArchive 的最后一个参数。请参阅添加的说明。
    猜你喜欢
    • 2014-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多