StringWriter 或 StringBuilder

StringWriterStringBuilder之间的区别是什么? 我什么时候应该使用它们?

35331 次浏览

StringWriter用于将文本写入 一份文件内存,StringBuilder用于以高效的内存方式将字符串附加在一起。

StringBuilder用于大量字符串串联。它更有效的超过5字符串,就我所知,然后 String.Concat()。它也可以使用特定的格式(.AppendFormat())

StringBuilder类基本上是一个可变的字符串,建造工程的一个助手类是一个不可变的字符串。构建在上面的 StringWriter为字符串格式化添加了更多方便的函数。

StringWriter 派生自 TextWriter,它允许各种类编写文本,而不必关心文本的去向。对于 StringWriter,输出只存在于内存中。如果调用的 API 需要 TextWriter,但是只想在内存中构建结果,那么可以使用这个函数。

StringBuilder 本质上是一个缓冲区,它允许您对“逻辑字符串”执行多个操作(通常附加) ,而不必每次都创建一个新的字符串对象。您可以使用它在多个操作中构造字符串。

我不认为现有的答案能真正回答这个问题。这两个类之间的实际关系是 适配器模式的一个例子。

StringWriter通过转发到它存储在字段中的 StringBuilder实例来实现它的所有 Write...方法。这不仅仅是一个内部细节,因为 StringWriter有一个返回内部字符串构建器的公共方法 GetStringBuilder,还有一个允许您传入现有 StringBuilder构造函数

因此,StringWriter是一个适配器,它允许 StringBuilder作为预期与 TextWriter一起工作的代码的目标。就基本行为而言,显然没有什么可以在它们之间做出选择... ... 除非你可以衡量转发呼叫的开销,在这种情况下,StringWriter会稍慢一些,但这似乎不太可能是显著的。

那么他们为什么不让 StringBuilder直接实现 TextWriter呢?这是一个灰色地带,因为界面背后的意图并不总是一目了然。

TextWriter非常接近,它是接收字符流的接口。但它还有一个额外的问题: 一个名为 编码中的属性。这意味着 TextWriter是接受字符流 并将它们转换为字节的接口。

这在 StringWriter中是一个无用的遗迹,因为它不执行编码。 文件说:

此属性对于某些 XML 方案是必需的,其中标头必须 包含 StringWriter 使用的编码 允许 XML 代码使用任意的 StringWriter 并生成 正确的 XML 标头。

但这不可能是正确的,因为我们没有办法为 StringWriter指定 Encoding的值。该属性始终具有值 UnicodeEncoding。因此,任何检查此属性以构建 XML 标头的代码都将始终使用 utf-16。例如:

var stringWriter = new StringWriter();
using (var xmlWriter = XmlWriter.Create(stringWriter))
xDocument.WriteTo(xmlWriter);

这就产生了标题:

<?xml version="1.0" encoding="utf-16"?>

如果使用 文件将 XML 字符串写入文件,会怎么样?默认情况下,您将拥有一个带有 utf-16头的 utf-8文件。

在这种情况下,使用 StreamWriter,并使用文件路径或 FileStream构造它,或者如果您想检查数据,那么使用 MemoryStream获取字节数组会更安全。所有这些组合将确保字节编码和头生成都是由 StreamWriter中相同的 Encoding值引导的。

Encoding属性的目的是允许字符流的生成器将有关编码的准确信息包含到字符流本身中(例如在 XML 示例中; 其他示例包括电子邮件头,等等)。

但是,通过引入 StringWriter,内容生成和编码之间的链接被打破,因此这种自动机制停止工作,并变得潜在的错误倾向。

尽管如此,如果您注意的话,StringWriter是一个非常有用的适配器,也就是说,您明白您的内容生成代码不应该依赖于 Encoding属性的无意义值。但是这种警告通常与适配器模式有关。这通常是一种技巧,可以让你把一个方形的,但几乎是圆形的钉子放进一个圆孔里。

在前面(好的)答案的基础上,StringWriter实际上比 StringBuilder通用得多,提供了大量的过载。

例如:

StringBuilder只接受字符串或 AppendLine不接受字符串

StringBuilder sb = new StringBuilder();
sb.AppendLine("A string");

StringWriter可以直接采用字符串格式

StringWriter sw = new StringWriter();
sw.WriteLine("A formatted string {0}", DateTime.Now);

对于 StringBuilder,必须这样做(或使用 string.Format$"")

sb.AppendFormat("A formatted string {0}", DateTime.Now);
sb.AppendLine();

不做或死的东西,但仍然是一个区别。

StringBuilderStringReader用于在不同情况下提高性能。
使用 StringBuilder可以提高字符串操作的性能,如串联、重复修改字符串。

Random rnd = new Random();
StringBuilder sb = new StringBuilder();


// Generate 10 random numbers and store in sb.
for (int i = 0; i < 10; i++)
{
sb.Append(rnd.Next().ToString("N5"));
}
Console.WriteLine("The original string:");
Console.WriteLine(sb.ToString());


// Decrease each number by one.
for (int ctr = 0; ctr < sb.Length; ctr++)
{
if (Char.GetUnicodeCategory(sb[ctr]) == System.Globalization.UnicodeCategory.DecimalDigitNumber)
{
int number = (int)Char.GetNumericValue(sb[ctr]);
number--;
if (number < 0)
number = 9;


sb[ctr] = number.ToString()[0];
}
}
Console.WriteLine("\nThe new string:");
Console.WriteLine(sb.ToString());

使用 StringReader分析单独行中的大量文本,并在处理数据时尽量减少内存使用。请参见下一个示例,其中 StringReader 上的 ReadLine 方法只扫描从当前位置开始的下一个换行,然后根据字段字符串返回 sbstring。

using (StringReader sr = new StringReader("input.txt"))
{
// Loop over the lines in the string or txt file.
int count = 0;
string line;
while((line = sr.ReadLine()) != null)
{
count++;
Console.WriteLine("Line {0}: {1}", count, line);
}
}