StringWriter或StringBuilder


Answers:


86

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

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

所以StringWriter是允许适配器StringBuilder用作目标的代码,希望与合作TextWriter。就基本行为而言,显然它们之间没有任何选择……除非您可以衡量转发呼叫的开销,否则这种情况StringWriter会稍慢一些,但这似乎不太可能。

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

TextWriter非常接近的,接受的字符流的东西接口。但是它还有一个额外的缺点:称为Encoding的属性。这意味着这TextWriter是一个接受字符流并将其转换为字节的对象的接口

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

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

但这是不对的,因为我们无法指定Encodingfor的值StringWriter。属性始终具有值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属性的无意义的值。但是这种警告通常与适配器模式有关。通常,这是一种技巧,可让您将方形但几乎是方形的圆钉插入圆孔中。


@SandRock见第二段
Daniel Earwicker,

您可以创建使用不同编码的派生StringWriter类型。
ejohnson '18

@Jon Skeet不是最佳射手的那些问题很少。
justAbit19年

56

StringWriter从派生TextWriter,它允许各种类编写文本而无需关心其去向。对于StringWriter,输出仅存入内存。如果要调用需要a的API,TextWriter但只想在内存中建立结果,则可以使用此方法。

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


8

在以前的(好的)答案的基础上,StringWriter实际上比StringBuilder具有更多的功能,并提供许多重载。

例如:

虽然Stringbuilder仅接受字符串,否则不接受附录

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();

没有做或死的东西,但还是有区别


3

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



0

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


您的最后一段适用于String Builder,而不适用于StringWriter。
康拉德·鲁道夫

1
。MSDN

0

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);
    }
}

我不明白任何人怎么会赞成这个答案。OP的问题StringWriter不是StringReader
Zev Spitz
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.