76

我应该使用其中一个或另一个之间有什么区别StringWriter以及StringBuilder何时使用?

4

7 回答 7

92

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

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

一个适配器也是如此StringWriter,它允许StringBuilder被期望与TextWriter. 就基本行为而言,它们之间显然没有任何选择......除非您可以测量转发呼叫的开销,在这种情况下StringWriter会稍微慢一些,但这似乎不太可能是重要的。

那么他们为什么不直接制作StringBuilder工具呢?TextWriter这是一个灰色地带,因为界面背后的意图并不一定总是乍一看很清楚。

TextWriter几乎是接受字符流的接口但它还有一个额外的问题:一个名为Encoding的属性。这意味着它TextWriter是一个接受字符流并将它们转换为字节的东西的接口。

这是一个无用的痕迹,StringWriter因为它不执行编码。文档说:

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

但这不可能是正确的,因为我们无法指定 for 的EncodingStringWriter。该属性始终具有值UnicodeEncoding。因此,任何检查此属性以在其中构建 XML 标头的代码总是会说utf-16. 例如:

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

这会产生标题:

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

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

StreamWriter在这种情况下,使用,并使用文件路径或 a 构造它会更安全FileStream,或者如果您想检查数据然后使用 aMemoryStream获得一个字节数组。所有这些组合将确保字节编码和标头生成由Encoding您的StreamWriter.

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

但是通过引入StringWriter,内容生成和编码之间的联系被打破,因此这种自动机制停止工作并变得容易出错。

然而,StringWriter如果您小心,它是一个有用的适配器,即您了解您的内容生成代码不应依赖于无意义的Encoding属性值。但是这种警告通常与适配器模式有关。这通常是一种技巧,可以让您将方形但几乎是圆形的钉子安装到圆孔中。

于 2012-06-15T10:29:28.890 回答
58

StringWriter派生自TextWriter,它允许各种类编写文本而不关心它的去向。在 的情况下StringWriter,输出只是进入内存。如果您正在调用需要 aTextWriter但您只想在内存中建立结果的 API,则可以使用它。

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

于 2009-03-02T13:13:32.220 回答
8

建立在以前的(好的)答案的基础上,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();

不做或死的东西,但仍然有区别。

于 2015-07-22T09:49:39.250 回答
3

该类StringBuilder基本上是一个可变字符串,一个构造不可变字符串的辅助类。StringWriter构建在顶部以添加更多方便的字符串格式化功能。

于 2009-03-02T13:09:46.753 回答
2

AStringWriter用于将文本写入一份文件memory 和 aStringBuilder用于以节省内存的方式将字符串附加在一起。

于 2009-03-02T13:07:36.727 回答
0

StringBuilder用于批量字符串连接。它对超过 5 个字符串更有效,据我所知,然后String.Concat(). 也可以与特定格式(.AppendFormat())一起使用

于 2009-03-02T13:07:52.827 回答
-1

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);
    }
}
于 2016-11-13T01:48:02.460 回答