StringWriter
和StringBuilder
之间的区别是什么?我应该何时使用其中一个?
答案 0 :(得分:78)
我认为任何现有的答案都不能真正回答这个问题。这两个类之间的实际关系是the adaptor pattern的一个例子。
StringWriter
通过转发到它存储在字段中的Write...
实例来实现其所有StringBuilder
方法。这不仅仅是一个内部细节,因为StringWriter
有一个公共方法GetStringBuilder,它返回内部字符串构建器,还有a constructor,它允许您传入现有的StringBuilder
所以StringWriter
是一个适配器,允许StringBuilder
被期望与TextWriter
一起使用的代码用作目标。在基本行为方面,显然没有什么可以在它们之间做出选择...除非你可以衡量转发呼叫的开销,在这种情况下StringWriter
稍微慢一点,但这似乎不太可能是重要的。
那么他们为什么不直接StringBuilder
实施TextWriter
?这是一个灰色区域,因为界面背后的意图乍一看并不一定清晰。
TextWriter
非常接近接受某个字符串的接口。但它有一个额外的皱纹:一个名为Encoding的属性。这意味着TextWriter
是接受字符流的东西的接口,并且还将它们转换为字节。
这是StringWriter
中无用的遗迹,因为它不执行编码。 documentation说:
此属性对于标头必须的某些XML方案是必需的 写入包含StringWriter使用的编码。这个 允许XML代码使用任意StringWriter并生成 正确的XML标题。
但这可能不对,因为我们无法为Encoding
指定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
更安全,并使用文件路径或FileStream
构建它,或者如果要检查数据,则使用MemoryStream
所以obtain an array of bytes。所有这些组合将确保编码到字节和标头生成由Encoding
中的相同StreamWriter
值引导。
Encoding
属性的目的是允许字符流的生成器将有关编码的准确信息包含在字符流本身中(例如在XML示例中;其他示例包括电子邮件标题等)
但是通过引入StringWriter
,内容生成和编码之间的链接被破坏,因此这种自动机制停止工作并且可能容易出错。
然而,StringWriter
是一个有用的适配器,如果你小心,即你了解你的内容生成代码不应该依赖于Encoding
属性的无意义值。但是这种警告通常与适配器模式有关。这通常是一种破解,允许你将一个方形但几乎是圆形的钉子安装到圆孔中。
答案 1 :(得分:54)
StringWriter
派生自TextWriter
,它允许各种类在不关心它的情况下编写文本。在StringWriter
的情况下,输出只是内存。如果你正在调用一个需要TextWriter
但你只想在内存中建立结果的API,你可以使用它。
StringBuilder
本质上是一个缓冲区,允许您对“逻辑字符串”执行多个操作(通常是附加),而不是每次都创建新的字符串对象。您可以使用它在多个操作中构造一个字符串。
答案 2 :(得分:5)
基于之前的(好的)答案,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();
不做或死的东西,但仍然是差异
答案 3 :(得分:3)
StringBuilder
类基本上是一个可变字符串,是构造一个不可变字符串的辅助类。 StringWriter
构建在顶部,为字符串格式化添加了更多便利功能。
答案 4 :(得分:2)
StringWriter
用于将文本写入文件内存,而StringBuilder
用于以高效内存的方式将字符串附加到一起。
答案 5 :(得分:0)
StringBuilder
和StringReader
用于改善不同情况下的表现
使用 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);
}
}
答案 6 :(得分:-1)
StringBuilder
用于批量串联连接。对于超过5个字符串,它更有效,据我所知,然后String.Concat()
。它也可以使用特定格式(.AppendFormat()
)