使用MemoryStream而不是FileStream时,无法保存更改

发布于 2025-01-19 08:24:30 字数 1470 浏览 6 评论 0原文

我有一个嵌入 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
  });

I have a DLL with embedded Excel file. The goal is to retrieve this file and create some entry (Empty_File.txt in this example). When I'm using FileStream - the entry gets created, but when I'm using MemoryStream - entry isn't created.

var filePath = "C:\\Temp\\Test2.xlsx";
var asm = typeof(Program).Assembly;
var asmName = asm.GetName().Name;
using var resourceStream = asm.GetManifestResourceStream(
quot;{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
  });

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

幻想少年梦 2025-01-26 08:24:30

per for ziparchive.dispose

此方法完成编写存档,并释放ziparchive对象使用的所有资源。除非您使用ziparchive(流,ZiparchiveMode,boolean)构建对象,否则构造函数过载并将其thepopen参数设置为true,所有基础流都已关闭,不再可用于随后的写操作。

您当前正在写入File Stream 之前,因此尚未编写zip文件的更改。

您还可以从中注意到,除非您在构造函数中指定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);
        }
    }
}

Per the docs for 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.

You are currently writing to the file stream before this happens, so the changes to the zip file haven't been written yet.

You'll also note from this that the underlying MemoryStream will be disposed unless you specify leaveOpen: true in the constructor, which would prevent you copying to the file afterwards.

So putting both of these together:

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);
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文