C# 将StringBuilder写入流

C# 将StringBuilder写入流,c#,stream,stringbuilder,C#,Stream,Stringbuilder,将StringBuilder写入System.IO.Stream的最佳方法是什么 我目前正在做: StringBuilder message = new StringBuilder("All your base"); message.Append(" are belong to us"); System.IO.MemoryStream stream = new System.IO.MemoryStream(); System.Text.ASCIIEncoding encoding = new

将StringBuilder写入System.IO.Stream的最佳方法是什么

我目前正在做:

StringBuilder message = new StringBuilder("All your base");
message.Append(" are belong to us");

System.IO.MemoryStream stream = new System.IO.MemoryStream();
System.Text.ASCIIEncoding encoding = new ASCIIEncoding();
stream.Write(encoder.GetBytes(message.ToString()), 0, message.Length);

不要使用StringBuilder,如果要写入流,请使用以下命令:


这是最好的方法。其他明智的做法是使用StringBuilder并使用以下内容:

using (MemoryStream ms = new MemoryStream())
{
    using (StreamWriter sw = new StreamWriter(ms, Encoding.Unicode))
    {
        sw.WriteLine("dirty world.");
    }
    //do somthing with ms
}

根据您的用例,从StringWriter开始也有意义:

StringBuilder sb = null;

// StringWriter - a TextWriter backed by a StringBuilder
using (var writer = new StringWriter())
{
    writer.WriteLine("Blah");
    . . .
    sb = writer.GetStringBuilder(); // Get the backing StringBuilder out
}

// Do whatever you want with the StringBuilder

也许它会有用

var sb= new StringBuilder("All your money");
sb.Append(" are belong to us, dude.");
var myString = sb.ToString();
var myByteArray = System.Text.Encoding.UTF8.GetBytes(myString);
var ms = new MemoryStream(myByteArray);
// Do what you need with MemoryStream

如果您想使用类似StringBuilder的东西,因为它更易于传递和使用,那么您可以使用类似于我创建的以下StringBuilder备选方案的东西

它所做的最重要的不同之处在于,它允许访问内部数据,而无需首先将其组装成字符串或ByteArray。这意味着您不必将内存需求翻一番,也不必冒着分配适合整个对象的连续内存块的风险

注意:我确信有比在内部使用
List()
更好的选项,但这很简单,并且证明对我来说已经足够好了

public class StringBuilderEx
{
    List<string> data = new List<string>();
    public void Append(string input)
    {
        data.Add(input);
    }
    public void AppendLine(string input)
    {
        data.Add(input + "\n");
    }
    public void AppendLine()
    {
        data.Add("\n");
    }

    /// <summary>
    /// Copies all data to a String.
    /// Warning: Will fail with an OutOfMemoryException if the data is too
    /// large to fit into a single contiguous string.
    /// </summary>
    public override string ToString()
    {
        return String.Join("", data);
    }

    /// <summary>
    /// Process Each section of the data in place.   This avoids the
    /// memory pressure of exporting everything to another contiguous
    /// block of memory before processing.
    /// </summary>
    public void ForEach(Action<string> processData)
    {
        foreach (string item in data)
            processData(item);
    }
}

我最近不得不做这件事,发现这个问题的答案并不令人满意

您可以将StringBuilder写入流,而无需具体化整个字符串:

StringBuilder StringBuilder=新建StringBuilder();
//将数据写入StringBuilder。。。
Stream=GetStream();//从某处获取输出流。
使用(var streamWriter=newstreamwriter(stream,Encoding.UTF8,leaveOpen:true))
{
foreach(stringBuilder.GetChunks()中的ReadOnlyMemory块)
{
等待streamWriter.WriteAsync(块);
}
}
注意:此API(StringBuilder.GetChunks())仅在.NET Core 3.0及更高版本中可用


如果此操作频繁发生,您可以通过使用StringBuilder对象池进一步降低GC压力。

如果他在编写之前需要将字符串用于其他用途,这是不可行的。绝对正确,但他当然没有说这是一个要求,所以我没有做任何假设。在从流中读取之前也要记住。非常确定:首先复制到字符串,然后再次复制到字节数组,最后复制到流中?真正地当然,这可以简洁地完成,而无需制作任何中间副本。(如果字符串生成器是2GB怎么办?)这是一种从StringBuilder提取数据的很酷的方法。一个警告是,这不是线程安全的,所以您应该在这段代码周围放置一个锁。我认为这是不必要的,您可以只做
streamWriter.WriteAsync(stringBuilder)
public class StringBuilderEx
{
    List<string> data = new List<string>();
    public void Append(string input)
    {
        data.Add(input);
    }
    public void AppendLine(string input)
    {
        data.Add(input + "\n");
    }
    public void AppendLine()
    {
        data.Add("\n");
    }

    /// <summary>
    /// Copies all data to a String.
    /// Warning: Will fail with an OutOfMemoryException if the data is too
    /// large to fit into a single contiguous string.
    /// </summary>
    public override string ToString()
    {
        return String.Join("", data);
    }

    /// <summary>
    /// Process Each section of the data in place.   This avoids the
    /// memory pressure of exporting everything to another contiguous
    /// block of memory before processing.
    /// </summary>
    public void ForEach(Action<string> processData)
    {
        foreach (string item in data)
            processData(item);
    }
}
var stringData = new StringBuilderEx();
stringData.Append("Add lots of data");

using (StreamWriter file = new System.IO.StreamWriter(localFilename))
{
    stringData.ForEach((data) =>
    {
        file.Write(data);
    });
}