ZipArchive 无法使用 MemoryStream 正确压缩文件

Iva*_*kin 1 .net compression zip

我正在使用 .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;
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我试图用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;
}
Run Code Online (Sandbox Code Playgroud)

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

xan*_*tos 5

在阅读之前,您必须“关闭”zip:

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();
Run Code Online (Sandbox Code Playgroud)

但是您必须将 设置ZipArchive为在流true关闭时使其保持“未处置”(最终)。

通过这种方式,zip 被“刷新”到流中。如果你注意到你在FileStream例子中做对了。

一般来说,你应该stream.Flush() 之前stream.Position = 0,因为它stream可能有一些未写的内部缓冲区,但这MemoryStream不是必需的,因为MemoryStream.Flush()

覆盖 Stream.Flush 方法,以便不执行任何操作