无法写入新的 MemoryStream - 流已关闭

Posted

技术标签:

【中文标题】无法写入新的 MemoryStream - 流已关闭【英文标题】:Cannot write to new MemoryStream - Stream closed 【发布时间】:2017-08-09 01:54:31 【问题描述】:

我有将一个或多个文件压缩为 tar(.gz) 或 zip 的方法。 在这些文件中,我使用已经加载到内存中的字节,我只需要将它们压缩,并将压缩文件写入 MemoryStream。

起初,我使用内存流引用来节省资源。 我开始收到来自应用程序的以下消息:

[MailArchive] [14:06] [Fatal] A fatal error occurred while executing the command "export-email" in the plugin RestService!
[MailArchive] [14:06] [Fatal] This error was not caught by the command handler and may have caused a severe application crash!
[MailArchive] [14:06] [Fatal] Error details are following:
[MailArchive] [14:06] [Trace] Cannot access a closed Stream.
[MailArchive] [14:06] [Trace] mscorlib
[MailArchive] [14:06] [Trace]    at System.IO.__Error.StreamIsClosed()
   at System.IO.MemoryStream.Seek(Int64 offset, SeekOrigin loc)
   at SharpCompress.Archives.AbstractWritableArchive`2.<>c.<SaveTo>b__18_0(IWritableArchiveEntry x)
   at SharpCompress.Utility.ForEach[T](IEnumerable`1 items, Action`1 action)
   at SharpCompress.Archives.AbstractWritableArchive`2.SaveTo(Stream stream, WriterOptions options)
   at SharpCompress.Archives.Zip.ZipArchive.SaveTo(Stream stream)
   at De.Nwt.MailArchive.MailProcessor_2.MailProcessor_2.CompressToZip(MemoryStream& memStream, IntFile[] files) in C:\Users\sc\Documents\Git\MailArchive\MailProcessor_2\Src\Classes\MailProcessor_2.FileIO.cs:line 312
   at De.Nwt.MailArchive.MailProcessor_2.MailProcessor_2.ExportAttachments(ArchiveType archType, String domain, String messageId, Boolean singleAttachment, String fName, Int32 idx) in C:\Users\sc\Documents\Git\MailArchive\MailProcessor_2\Src\Classes\MailProcessor_2.CommandHandling.cs:line 360
   at De.Nwt.MailArchive.MailProcessor_2.MailProcessor_2.Command_ExportEmail(Command sender, String[] args) in C:\Users\sc\Documents\Git\MailArchive\MailProcessor_2\Src\Classes\MailProcessor_2.CommandHandling.cs:line 192
   at De.Nwt.MailArchive.Commands.Command.Invoke(String[] args) in C:\Users\sc\Documents\Git\MailArchive\Command\Src\Classes\Command.cs:line 120
   at De.Nwt.MailArchive.MainClass.baseEvents_PluginExecutedCommand(Object sender, PluginExecutedCommandEventArgs e) in C:\Users\sc\Documents\Git\MailArchive\MailArchive\Src\Classes\MailArchive.cs:line 979
[MailArchive] [14:06] [Warn] Will return a CommandExceptionResult containing the above error!

收到这些错误后,我切换到对 MemoryStream 对象使用 out-parameters,即使在尝试使用内存流的多个新实例后,我仍然收到相同的错误。

其中一种方法如下:

    /// <summary>
    /// Compresses one or more files to a zip archive.
    /// </summary>
    /// <param name="memStream">The memory stream.</param>
    /// <param name="files">The files.</param>
    void CompressToZip(out MemoryStream memStream, params MailProcessor_2.IntFile[] files) 
        using (var zipArchive = ZipArchive.Create()) 
            foreach (var file in files) 
                using (var _memStream = new MemoryStream(file.Contents)) 
                    zipArchive.AddEntry(file.Filename, _memStream, _memStream.Length);
                
            

            var tmpStream = new MemoryStream();
            zipArchive.SaveTo(tmpStream); // The error occurrs here
            memStream = tmpStream;
        
    

我已经通过调试器,并在错误发生的地方设置了一个断点,tmpStream 的 _isOpen 变量设置为 true。

任何有关此事的帮助将不胜感激。


编辑:我忘了提到我正在使用 SharpCompress 进行 Tar-archival 和 Zip 压缩。对于 Gzip 压缩,我使用的是标准的 .Net 框架。

【问题讨论】:

_memStream = 中去掉使用,写成var _memStream = 。也许AddEntry 拥有MemoryStream 的所有权 这不是 Microsoft ZipArchive 类 - 它来自哪里? 啊...下次 .NET 十亿个库中的一个崩溃时,您至少应该告诉我们它是哪一个 :-) 哈哈哈,抱歉,我匆忙忘记补充了。我使用 SharpCompress 进行 Tar/Zip 压缩,使用标准 .Net 类压缩到 Gzip 文件。我会把它添加到 OP 中。 删除了使用,它再次完美运行。您可以将其添加为答案吗?我会将其标记为已接受的答案。 【参考方案1】:

正如我所怀疑的,代码拥有您作为文件传递的Stream 的所有权,所以您不能Close()/Dispose() 它...

写成:

var _memStream = new MemoryStream(file.Contents);
zipArchive.AddEntry(file.Filename, _memStream, true);

它应该使用this overload。 true 是为了在不使用时关闭Stream

它可能会自动发现length(我看到它是一个可选值,默认为0

【讨论】:

以上是关于无法写入新的 MemoryStream - 流已关闭的主要内容,如果未能解决你的问题,请参考以下文章

写入 CSV 文件:IOException:流已关闭

如何将 MemoryStream 写入字节 [] [重复]

3 分钟无操作后,Firestore“流已删除”错误

将序列化的 HttpResponseMessage 缓存到 Redis。读取错误。 “InvalidOperationException:流已被消耗。无法再次读取。”

MemoryStream - 无法访问已关闭的流

不同的线程访问 MemoryStream