【问题标题】:StringWriter or StringBuilderStringWriter 或 StringBuilder
【发布时间】:2010-10-10 18:40:31
【问题描述】:

StringWriterStringBuilder 之间有什么区别,我什么时候应该使用其中一个?

【问题讨论】:

    标签: .net stringbuilder stringwriter


    【解决方案1】:

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

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

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

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

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

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

    对于某些必须有标头的 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"?>
    

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

    在这种情况下,使用StreamWriter 会更安全,并使用文件路径或FileStream 构造它,或者如果您想检查数据然后使用MemoryStreamobtain an array of bytes。所有这些组合将确保字节编码和标头生成由您的StreamWriter 中相同的Encoding 值指导。

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

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

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

    【讨论】:

    • @SandRock 见第二段
    • 您可以创建一个派生的StringWriter 类型,其中uses a different encoding
    • @Jon Skeet 不是最佳得分手的问题很少。
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

      不做也不做,但还是有区别的。

      【讨论】:

        【解决方案4】:

        StringBuilder 类基本上是一个可变字符串,是一个构造不可变字符串的辅助类。 StringWriter 是在上面构建的,为字符串格式化添加了更多便利功能。

        【讨论】:

          【解决方案5】:

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

          【讨论】:

            【解决方案6】:

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

            【讨论】:

            【解决方案7】:

            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
            猜你喜欢
            • 2023-03-21
            • 1970-01-01
            • 2018-07-26
            • 2014-09-17
            • 2018-07-27
            • 1970-01-01
            • 2013-06-17
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多