使用System.IO.Compression.ZipArchive

时间:2016-01-26 19:16:23

标签: c#

将字符串转换为压缩文本文件的辅助方法:

public static System.Net.Mail.Attachment CreateZipAttachmentFromString(string content, string filename)
{
  using (MemoryStream memoryStream = new MemoryStream())
  {
    using (ZipArchive zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Update))
    {
      ZipArchiveEntry zipArchiveEntry = zipArchive.CreateEntry(filename);
      using (StreamWriter streamWriter = new StreamWriter(zipArchiveEntry.Open()))
      {
        streamWriter.Write(content);
      }

    }

    MemoryStream memoryStream2 = new MemoryStream(memoryStream.ToArray(), false);

    return new Attachment(memoryStream2, filename + ".zip", MediaTypeNames.Application.Zip);
  }
}

我真的希望避免将第一个内存流转换为数组,在其上创建另一个内存流来读取它,并将其传递给附件。我的逻辑是,为什么将X兆字节复制到内存中的另一个位置以建立另一个指向副本的流,当它基本上就是我们开始的时候......它是像MB {1}}那样的多兆字节等价的冗余>

所以我想,我会回到第一个内存流的开始,然后附件可能只是读取..或者我将建立指向第一个缓冲区的另一个内存流,并使用offset和length参数这样设置就知道要读什么了

这些方法都没有解决,因为当控件落在使用块之外并且处理了ziparchive时,ZipArchive似乎只将数据推入内存流(在我的情况下可能)。处理它也会释放MemoryStream,几乎所有东西(除了ToArray()和GetBuffer()之外)都会抛出ObjectDisposedException。

最终我无法在ZipArchive将数据泵入其中并在泵入之前找到它或获得它的长度,偏移量通常为零,长度肯定为零,因此值无用

是否有一个很好的最佳方式,没有配置我自己的超大缓冲区(然后使其不能被MemoryStream扩展),以避免使用这种方法烧掉存档大小的2倍内存字节? / p>

3 个答案:

答案 0 :(得分:4)

.NET中大多数设计良好的流和流用户都有一个额外的布尔参数,可用于指示他们在处理时打开“基本流”(可怕名称)。

这是ZipArchive的{​​{3}}:

public ZipArchive(
    Stream stream,
    ZipArchiveMode mode,
    bool leaveOpen
)

答案 1 :(得分:1)

不需要第二个MemoryStream。你需要做两件事:

  1. 确保MemoryStream未在最后一个使用点之前处理。这是无害的。处置MemoryStream没有任何帮助,出于兼容性原因,将来永远不会做任何事情。 .NET Framework具有非常高兼容性栏。他们往往不敢重新命名。
  2. 寻求抵消零。
  3. 请移除using周围的MemoryStream并使用ZipArchive的ctor,以便让您打开流。

    由于您要返回的Attachment使用MemoryStream,因此您无法在退出方法之前对其进行处理。再次,这是无害的。唯一的缺点是代码变得不那么明显了。

    这是一种完全不同的方法:您可以编写自己的Stream类,按需创建字节。这样就根本不需要缓冲字符串和ZIP字节。当然,这是更多的工作。并且它并没有减损整个字符串必须同时存在于内存中的事实,因此它仍然不是O(1)空间解决方案。

答案 2 :(得分:0)

    public static System.Net.Mail.Attachment CreateZipAttachmentFromString(string content, string filename)
    {
        MemoryStream memoryStream = new MemoryStream();

        using (ZipArchive zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Update, true))
        {
            ZipArchiveEntry zipArchiveEntry = zipArchive.CreateEntry(filename);
            using (StreamWriter streamWriter = new StreamWriter(zipArchiveEntry.Open()))
            {
                streamWriter.Write(content);
            }

        }

        memoryStream.Position = 0;

        return new Attachment(memoryStream, filename + ".zip", MediaTypeNames.Application.Zip);
    }