В чем разница между StringWriter
и StringBuilder
и когда я должен использовать один или другой?
StringWriter или StringBuilder
Ответ 1
Я не думаю, что любой из существующих ответов действительно отвечает на вопрос. Фактическая взаимосвязь между двумя классами является примером шаблона адаптера.
StringWriter
реализует все свои методы Write...
путем пересылки на экземпляр StringBuilder
, который он хранит в поле. Это не просто внутренняя деталь, потому что StringWriter
имеет открытый метод GetStringBuilder, который возвращает внутренний построитель строк, а также конструктор, который позволяет вам передать существующий StringBuilder
.
Итак, StringWriter
- это адаптер, который позволяет использовать StringBuilder
в качестве цели кодом, который ожидает работать с TextWriter
. С точки зрения базового поведения явно нечего выбирать между ними... если вы не можете измерить накладные расходы на переадресацию вызовов, и в этом случае StringWriter
будет немного медленнее, но это кажется очень маловероятным.
Так почему же они не сделали StringBuilder
реализовать TextWriter
напрямую? Это серая область, потому что намерение интерфейса не обязательно всегда ясно на первый взгляд.
TextWriter
- это почти интерфейс для чего-то, что принимает поток символов. Но у него есть дополнительная морщина: свойство, называемое Encoding. Это означает, что TextWriter
является интерфейсом к тому, что принимает поток символов, а также преобразует их в байты.
Это бесполезный остаток в StringWriter
, потому что он не выполняет кодировку. В документации говорится:
Это свойство необходимо для некоторых сценариев 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
и, таким образом, получить массив байтов. Все эти комбинации гарантировали бы, что кодирование в байтах и генерация заголовка будет руководствоваться одним и тем же значением Encoding
в вашем StreamWriter
.
Цель свойства Encoding
заключалась в том, чтобы позволить генераторам потоков символов включать точную информацию о кодировании в сам поток символов (например, в примере XML, другие примеры включают заголовки электронной почты и т.д.)
Но, введя StringWriter
, эта связь между созданием и кодированием контента нарушена, и поэтому такие автоматические механизмы перестают работать и становятся потенциально подверженными ошибкам.
Тем не менее, StringWriter
является полезным адаптером, если вы осторожны, то есть понимаете, что код генерации вашего контента не должен зависеть от бессмысленного значения свойства Encoding
. Но такое предостережение обычно связано с шаблоном адаптера. Это часто своего рода хак, позволяющий вам приспосабливать квадратный-но-почти круглый штырь в круглое отверстие.
Ответ 2
StringWriter
происходит от TextWriter
, который позволяет различным классам писать текст, не заботясь о том, куда он идет. В случае StringWriter
вывод поступает в память. Вы бы использовали это, если вы вызываете API, которому требуется TextWriter
, но вы хотите только создать результаты в памяти.
StringBuilder
- это, по сути, буфер, который позволяет выполнять несколько операций (обычно прилагается) к "логической строке" без создания нового Строковый объект каждый раз. Вы должны использовать это для построения строки в нескольких операциях.
Ответ 3
Класс StringBuilder
- это, в основном, изменяемая строка, вспомогательный класс для построения неизменяемой строки. StringWriter
построен сверху, чтобы добавить дополнительные функции удобства для форматирования строк.
Ответ 4
A StringWriter
используется для записи текста в файл и StringBuilder
используется для добавления строк вместе с эффективностью памяти.
Ответ 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();
Не делай и не умирай, но все-таки разница
Ответ 6
StringBuilder
используется для массовой конкатенации строк. Это более эффективно для более чем 5 строк, насколько я знаю, тогда String.Concat()
. Также он может использоваться с определенным форматом (.AppendFormat()
)
Ответ 7
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
для синтаксического анализа большого количества текста в отдельных строках и минимизации использования памяти во время обработки данных. См. Следующий пример, в котором метод ReadLine на StringReader просто сканирует следующую строку новой строки, начиная с текущей позиции, а затем возвращает строку 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);
}
}