StringWriter или StringBuilder - PullRequest
62 голосов
/ 02 марта 2009

В чем разница между StringWriter и StringBuilder и когда мне следует использовать один или другой?

Ответы [ 7 ]

78 голосов
/ 15 июня 2012

Я не думаю, что какой-либо из существующих ответов действительно отвечает на вопрос. Фактические отношения между двумя классами являются примером шаблона адаптера .

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. Но такого рода предостережения обычно связаны с шаблоном адаптера. Часто это своего рода хакерство, позволяющее вам вставить квадратный колышек в круглое отверстие.

54 голосов
/ 02 марта 2009

StringWriter происходит от TextWriter, что позволяет различным классам писать текст, не обращая внимания на то, куда он идет. В случае StringWriter вывод находится только в памяти. Вы можете использовать это, если вы вызываете API, которому требуется TextWriter, но вы хотите создавать результаты только в памяти.

StringBuilder - это, по сути, буфер, который позволяет выполнять несколько операций (обычно добавляет) к «логической строке», не создавая каждый раз новый строковый объект. Вы могли бы использовать это для создания строки в нескольких операциях.

5 голосов
/ 22 июля 2015

Основываясь на предыдущих (хороших) ответах, 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 голосов
/ 02 марта 2009

Класс StringBuilder в основном является изменяемой строкой, вспомогательный класс для создает неизменную строку. StringWriter построен сверху, чтобы добавить больше удобных функций для форматирования строк.

2 голосов
/ 02 марта 2009

A StringWriter используется для записи текста в файл памяти, а StringBuilder используется для добавления строк вместе с эффективным использованием памяти образом.

0 голосов
/ 13 ноября 2016

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);
    }
}
0 голосов
/ 02 марта 2009

StringBuilder используется для массовой конкатенации строк. Это более эффективно для более чем 5 строк, насколько я знаю, тогда String.Concat(). Также может использоваться с определенным форматом (.AppendFormat())

...