使用 MemoryStream 而不是 FileStream 时不会保存更改

Changes are not save when using MemoryStream instead of FileStream

我有一个带有嵌入式 Excel 文件的 DLL。目标是检索此文件并创建一些条目(在此示例中为 Empty_File.txt)。当我使用 FileStream 时 - 条目已创建,但当我使用 MemoryStream 时 - 条目未创建。

var filePath = "C:\Temp\Test2.xlsx";
var asm = typeof(Program).Assembly;
var asmName = asm.GetName().Name;
using var resourceStream = asm.GetManifestResourceStream($"{asmName}.Resources.Template.xlsx");

if (File.Exists(filePath)) File.Delete(filePath);

await UseFileStream(resourceStream, filePath);
// or
await UseMemoryStream(resourceStream, filePath);


static async Task UseMemoryStream(Stream resourceStream, string filePath)
{
  using (var ms = new MemoryStream())
  {
    await resourceStream.CopyToAsync(ms);
    using (var zip = new ZipArchive(ms, ZipArchiveMode.Update))
    {
      zip.CreateEntry("Empty_File.txt");
      using (var fs = CreateFileStream(filePath))
      {
        ms.Seek(0L, SeekOrigin.Begin);
        await ms.CopyToAsync(fs);
      }
    }
  }
}

static async Task UseFileStream(Stream resourceStream, string filePath)
{
  using var fs = CreateFileStream(filePath);
  await resourceStream.CopyToAsync(fs);
  using var zip = new ZipArchive(fs, ZipArchiveMode.Update);
  zip.CreateEntry("Empty_File.txt");
}

static FileStream CreateFileStream(string filePath) =>
  new FileStream(filePath, new FileStreamOptions
  {
    Access = FileAccess.ReadWrite,
    Mode = FileMode.Create,
    Share = FileShare.None
  });

the docs 对于 ZipArchive.Dispose:

This method finishes writing the archive and releases all resources used by the ZipArchive object. Unless you construct the object by using the ZipArchive(Stream, ZipArchiveMode, Boolean) constructor overload and set its leaveOpen parameter to true, all underlying streams are closed and no longer available for subsequent write operations.

您当前正在写入文件流之前发生这种情况,因此尚未写入对 zip 文件的更改。

您还会从中注意到,除非您在构造函数中指定 leaveOpen: true,否则底层 MemoryStream 将被释放,这会阻止您之后复制到文件。

所以把这两个放在一起:

static async Task UseMemoryStream(Stream resourceStream, string filePath)
{
    using (var ms = new MemoryStream())
    {
        await resourceStream.CopyToAsync(ms);
        using (var zip = new ZipArchive(ms, ZipArchiveMode.Update, leaveOpen: true))
        {
            zip.CreateEntry("Empty_File.txt");
        }
        using (var fs = CreateFileStream(filePath))
        {
            ms.Seek(0L, SeekOrigin.Begin);
            await ms.CopyToAsync(fs);
        }
    }
}