StringBuilder与StringWriter/StringReader的区别

36

我最近读到,在 StringWriterStringReader 中被用于向 StringBuilder 写入和读出数据。

但是当我使用 StringBuilder 对象时,它似乎是一个自给自足的类。

我们可以使用 StringBuilder.Append(), Insert(), Replace(), Remove() 等方式来读写 StringBuilder

  1. StringWriterStringReader 的可能用途是什么?这些用途不能被 StringBuilder 自身完成吗?
  2. 它们的实际应用是什么?
  3. 它们为什么不将 Stream 作为输入(因为任何其他的 writer 和 reader 都将流作为构造函数参数来进行操作),而是使用 StringBuilder

1
可能是StringWriter或StringBuilder的重复 - Tim Abell
4个回答

37

StringWriter和StringReader有什么可能的用途,StringBuilder本身不能完成吗?

StringReaderStringWriter都派生自TextReaderTextWriter。因此,它们可以像TextReaderTextWriter实例一样工作,而stringStringBuilder不能,因为它们都没有派生这些类型。

它们的实际用途是什么?

它们允许您调用期望TextReaderTextWriter的API,当您拥有/想要的是stringStringBuilder时。

它们为什么不采用Stream作为输入(因为任何其他writer和reader都将流作为构造函数参数来操作),而是采用StringBuilder?

因为它们不能在流上工作;它们只能在字符串或StringBuilder上工作。它们只是简单的包装类,用于适配期望不同接口的API。参见:适配器模式

7

其他人已经说过了,但是这是因为它们派生自TextReader/TextWriter并且可以用于它们的位置。首先,如果您只想要内容作为字符串,则使用相同的方法输出行比使用文件更有意义。如果您需要在内存中跨越多行的输出,为什么要记得在StringBuilder的每一行末尾加上"\r\n"呢?如果您希望代码在或格式化数据的系统上运行,该系统仅使用"\n"作为换行符怎么办?

StringBuilder sb = new StringBuilder();
// will be invalid on systems that only use \n
sb.AppendFormat("{0:yyyy-MM-dd HH:mm:ss} - Start\r\n", DateTime.Now);
// still have to add an extra parameter
sb.AppendFormat("The current time is {0:yyyy-MM-dd HH:mm:ss}{1}", DateTime.Now,
    Environment.NewLine);

StringWriter sw = new StringWriter();
// Don't have to worry about it, method name tells you there's a line break
sw.WriteLine("{0:yyyy-MM-dd HH:mm:ss} - Start", DateTime.Now);
// no extra parameters
sw.WriteLine("The current time is {0:yyyy-MM-dd HH:mm:ss}", DateTime.Now);

如果你想逐行处理文件,你可能会使用StreamReader而不是将整个文件加载到StringBuilder中并通过换行符拆分为数组,对吧?使用StringReader,只要它采用通用的TextReader,就可以使用完全相同的方法,从TextBox或Web表单中创建字符串并将其转换为StringReader。

Linq2Sql DataContexts具有Log属性,您可以将其设置为TextWriter,以便在执行查询之前输出查询以查看正在运行的内容。您可以将其设置为附加到文件的TextWriter,但是在测试时,您可以将其附加到StringWriter上,并在网页底部输出其内容......


StringBuilder有一个AppendLine方法,它可以在末尾添加一个换行符。 - reggaeguitar

1
您可以使用StringReader从字符串中读取所有整数。
private static void Main()
{
    var str = @"
                13
                13
                0 6
                0 5
                0 1
                0 2
                5 3
                6 4
                5 4
                3 4
                7 8
                9 10
                11 12
                9 11
                9 12";


    using (StandardInput input = new StandardInput(new StringReader(str)))
    {
        List<int> integers = new List<int>();
        int n;
        while ((n = input.ReadInt32()) != -1)
        {
            integers.Add(n);
        }
    }
}

标准输入类:

class StandardInput : IDisposable
{
    private readonly TextReader reader;

    public StandardInput(TextReader reader)
    {
        this.reader = reader;
    }

    public int ReadInt32()
    {
        while (!char.IsDigit((char)reader.Peek()) && reader.Peek() != -1)
        {
            reader.Read();
        }
        var builder = new StringBuilder();
        while (char.IsDigit((char) reader.Peek()))
            builder.Append((char) reader.Read());

        return builder.Length == 0 ? -1 : int.Parse(builder.ToString());
    }

    public double ReadDouble()
    {
        while (!char.IsDigit((char)reader.Peek()) && reader.Peek() != '.'
                                                  && reader.Peek() != -1)
        {
            reader.Read();
        }
        var builder = new StringBuilder();
        if (reader.Peek() == '.')
            builder.Append((char) reader.Read());
        while (char.IsDigit((char)reader.Peek()))
            builder.Append((char)reader.Read());
        if (reader.Peek() == '.' && !builder.ToString().Contains("."))
        {
            builder.Append((char)reader.Read());
            while (char.IsDigit((char)reader.Peek()))
                builder.Append((char)reader.Read());
        }
        return builder.Length == 0 ? -1 : double.Parse(builder.ToString());
    }

    public void Dispose()
    {
        reader.Dispose();
    }
}

0
我不确定是谁告诉你它们的目的是与StringBuilder一起使用的,但这完全是不正确的。正如您所指出的,StringBuilder可以在没有其他类的情况下进行读取和写入。StringWriter和StringReader类扩展了TextReader和TextWriter .Net Framework基类,并提供了用于处理文本数据的类似流的功能。例如,如果您需要使用某些XmlDocument类型的类,一些方法允许您通过TextReader加载Xml数据,因此,如果您具有Xml文本作为字符串变量,您可以将其加载到StringReader中,然后将其提供给XmlDocument。

嗨,谢谢你的回答。我同意这一点,它是从TextWriter/TextReader派生而来的。例如,我拿StringWriter为例,发现以下两个初始化都不起作用。 FileStream fs = new FileStream(@"C:\Users\Saravanan\Documents\something.bin", FileMode.OpenOrCreate); StringWriter sw1 = File.CreateText(@"C:\Users\Saravanan\Documents\something.bin"); StringWriter sw2 = new StringWriter(fs);只有使用Stringbuilder才能写入。 - SaravananArumugam
1
@Saravanandss - 如果你想要从/向流中读写数据,那么请使用 StreamReaderStreamWriter... 这就是它们存在的目的。StringReaderStringWriter 不是为了处理文件而设计的;它们是为了处理字符串而设计的。你为什么要使用它们呢? - Greg Beech

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接