向内存流追加数据

9

我正在尝试向流中添加一些数据。这对于FileStream来说效果很好,但对于MemoryStream来说却不行,因为它具有固定的缓冲区大小。

写入数据到流的方法与创建流的方法分离(在下面的示例中已大大简化)。创建流的方法不知道要写入流的数据长度。

public void Foo(){
    byte[] existingData = System.Text.Encoding.UTF8.GetBytes("foo");
    Stream s1 = new FileStream("someFile.txt", FileMode.Append, FileAccess.Write, FileShare.Read);
    s1.Write(existingData, 0, existingData.Length);


    Stream s2 = new MemoryStream(existingData, 0, existingData.Length, true);
    s2.Seek(0, SeekOrigin.End); //move to end of the stream for appending

    WriteUnknownDataToStream(s1);
    WriteUnknownDataToStream(s2); // NotSupportedException is thrown as the MemoryStream is not expandable
}

public static void WriteUnknownDataToStream(Stream s)
{
   // this is some example data for this SO query - the real data is generated elsewhere and is of a variable, and often large, size.
   byte[] newBytesToWrite = System.Text.Encoding.UTF8.GetBytes("bar"); // the length of this is not known before the stream is created.
   s.Write(newBytesToWrite, 0, newBytesToWrite.Length);
}

我的一个想法是将可扩展的MemoryStream发送到函数中,然后将返回的数据附加到现有数据中。

public void ModifiedFoo()
{
   byte[] existingData = System.Text.Encoding.UTF8.GetBytes("foo");
   Stream s2 = new MemoryStream(); // expandable capacity memory stream

   WriteUnknownDataToStream(s2);

   // append the data which has been written into s2 to the existingData
   byte[] buffer = new byte[existingData.Length + s2.Length];
   Buffer.BlockCopy(existingData, 0, buffer, 0, existingData.Length);
   Stream merger = new MemoryStream(buffer, true);
   merger.Seek(existingData.Length, SeekOrigin.Begin);
   s2.CopyTo(merger);
}

有更好(更高效)的解决方案吗?

3
请问您为什么不使用可扩展流(expandable stream)来进行写操作? - Rotem
1
啊,像这样吗? Stream s2 = new MemoryStream(); // 可扩展容量的内存流s2.Write(existingData, 0, existingData.Length);WriteUnknownDataToStream(s2); - Iain Sproat
是的,那就是我的意思...这就是为什么它是一个流而不是一个数组,不是吗? - Rotem
1
@Rotem @sprocketonline 其中一位应该将其发布为答案。 - svick
1
只需创建一个MemoryStream,将existingData附加到该流中,然后继续向其中附加数据即可。 - Peter Ritchie
1个回答

29

一种可能的解决方法是不要在一开始就限制 MemoryStream 的容量。 如果您事先不知道需要写入多少字节,请创建一个未指定容量的 MemoryStream 并将其用于写入。

byte[] existingData = System.Text.Encoding.UTF8.GetBytes("foo");
MemoryStream ms = new MemoryStream();
ms.Write(existingData, 0, existingData.Length); 
WriteUnknownData(ms);

这种方法的性能无疑会比从byte[]初始化一个MemoryStream要差一些,但如果你需要继续向流中写入数据,我认为这是你唯一的选择。


1
如果性能差异很重要,您可以指定流的初始容量。这样,如果您猜测(或知道)最终大小,就不会有任何重新分配。如果你猜得不好,你会浪费内存或有重新分配影响性能,但它仍然可以工作。 - svick

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接