StringWriter 或 StringBuilder

发布于 2024-07-14 22:12:47 字数 81 浏览 17 评论 0原文

StringWriterStringBuilder 之间有什么区别?何时应该使用其中之一?

What is the difference between StringWriter and StringBuilder and when should I use one or the other?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

锦上情书 2024-07-21 22:12:47

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

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

因此,StringWriter 是一个适配器,允许希望与 TextWriter 一起使用的代码将 StringBuilder 用作目标。 就基本行为而言,它们之间显然没有什么可选择的...除非您可以测量转发调用的开销,在这种情况下 StringWriter 稍微慢一些,但这似乎不太可能很重要。

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

TextWriter非常是一个接受字符流的接口。 但它还有一个额外的问题:一个名为 Encoding。 这意味着 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"?>

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

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

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

但通过引入 StringWriter,内容生成和编码之间的链接被破坏,因此此类自动机制将停止工作并可能容易出错。

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

I don't think any of the existing answers really answer the question. The actual relationship between the two classes is an example of the adapter pattern.

StringWriter implements all its Write... methods by forwarding on to an instance of StringBuilder that it stores in a field. This is not merely an internal detail, because StringWriter has a public method GetStringBuilder that returns the internal string builder, and also a constructor that allows you to pass in an existing StringBuilder.

So StringWriter is an adaptor that allows StringBuilder to be used as a target by code that expects to work with a TextWriter. In terms of basic behaviour there is clearly nothing to choose between them... unless you can measure the overhead of forwarding the calls, in which case StringWriter is slightly slower, but that seems very unlikely to be significant.

So why didn't they make StringBuilder implement TextWriter directly? This is a grey area, because the intention behind an interface is not necessarily always clear at first glance.

TextWriter is very nearly an interface to something that accepts a stream of characters. But it has an additional wrinkle: a property called Encoding. This implies that TextWriter is an interface to something that accepts a stream of characters and also converts them into bytes.

This is a useless vestige in StringWriter because it performs no encoding. The documentation says:

This property is necessary for some XML scenarios where a header must
be written containing the encoding used by the StringWriter. This
allows the XML code to consume an arbitrary StringWriter and generate
the correct XML header.

But that can't be right, because there is no way for us to specify the value of Encoding for StringWriter. The property always has the value UnicodeEncoding. Consequently any code that examined this property to build an XML header into would always say utf-16. For example:

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

That produces the header:

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

What if you used File.WriteAllText to write your XML string to a file? By default, you'd then have a utf-8 file with a utf-16 header.

In such scenarios it would be safer to use StreamWriter, and construct it with a file path, or a FileStream, or if you want to examine the data then use a MemoryStream and so obtain an array of bytes. All these combinations would ensure that the encoding to bytes and the header generation were being guided by the same Encoding value in your StreamWriter.

The aim of the Encoding property was to allow generators of character streams to include accurate information about the encoding into the character stream itself (such as in the XML example; other examples include email headers, and so on).

But by introducing StringWriter, that link between content generation and encoding is broken, and so such automatic mechanisms stop working and become potentially error prone.

Nevertheless, StringWriter is a useful adaptor if you are careful, i.e. you understand that your content generation code should not depend on the meaningless value of the Encoding property. But that kind of caveat is commonly associated with the adaptor pattern. It's often a sort of hack to allow you to fit a square-ish-but-almost round peg into a round hole.

蓝眸 2024-07-21 22:12:47

StringWriter 源自 < a href="http://msdn.microsoft.com/en-us/library/system.io.textwriter.aspx" rel="noreferrer">TextWriter,它允许各种编写文本而不关心文本去向的类。 对于StringWriter,输出只是进入内存。 如果您调用的 API 需要 TextWriter 但您只想在内存中构建结果,则可以使用此方法。

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

StringWriter derives from TextWriter, which allows various classes to write text without caring where it's going. In the case of StringWriter, the output is just into memory. You would use this if you're calling an API which needs a TextWriter but you only want to build up results in memory.

StringBuilder is essentially a buffer which allows you to perform multiple operations (typically appends) to a "logical string" without creating a new string object each time. You would use this to construct a string in multiple operations.

不如归去 2024-07-21 22:12:47

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

不是做或死的事情,但仍然有区别。

Building on the previous (good) answers, StringWriter is actually much more versatile than StringBuilder, providing lots of overloads.

For example:

While StringBuilder only accepts a string or nothing for AppendLine

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

StringWriter can take a string format directly

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

With StringBuilder, one must do this (or use string.Format, or $"")

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

Not do or die stuff, but still a difference.

救星 2024-07-21 22:12:47

StringBuilder 类基本上是一个可变字符串,是一个用于构造不可变字符串的辅助类。 StringWriter 构建于其之上,为字符串格式化添加更多便利函数。

The StringBuilder class is basically a mutable string, a helper class to construct an immutable string. The StringWriter is built on top to add more convenience functions for string formatting.

空心↖ 2024-07-21 22:12:47

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

A StringWriter is used to write text to a file memory and a StringBuilder is used to append strings together in a memory-efficient manner.

ㄟ。诗瑗 2024-07-21 22:12:47

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

StringBuilder and StringReader are used to improve performance in different situations.
Use StringBuilder to improve performance on string manipulation such as concatenation, modifying string repeatedly.

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

Use StringReader to parse a large amount of text in separate lines and minimize memory use while processing data. See next example where ReadLine method on StringReader simply scans for the next newline starting at the current postion, and then return a sbstring based on the field string.

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);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文