StringReader省略了尾随换行符

时间:2013-10-14 17:03:20

标签: c# .net io

我注意到在ReadLine()StreamReader上使用StringReader时,如果文件或字符串以换行符结尾,则该字符序列将完全丢失。请考虑以下示例:

static void Main(string[] args)
{
    string data = "First Line\r\nSecond Line\r\n\r\n\r\n";
    List<string> lineData = new List<string>();
    string[] splitData = data.Split(
        new string[] { "\r\n" }, 
        StringSplitOptions.None);

    using (StringReader sr = new StringReader(data))
    {
        string line;
        while ((line = sr.ReadLine()) != null)
            lineData.Add(line);
    }

    Console.WriteLine("Raw Line Count: " + splitData.Length);
    Console.WriteLine("StringReader Line Count: " + lineData.Count);
    Console.WriteLine("Split Data: ");
    foreach (string s in splitData)
        Console.WriteLine(string.IsNullOrEmpty(s) ? "[blank line]" : s);
    Console.WriteLine("StringReader Data: ");
    foreach (string s in lineData)
        Console.WriteLine(string.IsNullOrEmpty(s) ? "[blank line]" : s);
    Console.ReadKey();
}

输出如下:

Raw Line Count: 5
StringReader Line Count: 4
Split Data:
First Line
Second Line
[blank line]
[blank line]
[blank line]
StringReader Data:
First Line
Second Line
[blank line]
[blank line]

StringReader / StreamReader为何如此表现?我可以想到几种解决方法,但是由于读者的行为方式不正常,因此重新编写代码似乎很愚蠢。某些.NET库中是否存在某些设置会影响流处理最终换行符的方式?

修改

以下是另一个示例:首先针对"First Line\r\nSecond Line"运行示例,然后针对"First Line\r\nSecond Line\r\n"比较结果。结果完全相同(就示例的StringReader部分而言)。为什么StringReader会在第二个示例中返回null而不是空字符串?我知道从ReadLine()返回的字符串不包含换行符,但为什么最后一行被解释为null而不是""

3 个答案:

答案 0 :(得分:3)

输出的差异不是因为StringReader的奇怪行为。请注意,您的输入只包含四行,并且正在读取正好四行(仅有documentation指定的结尾换行符号)。这是引入额外行的Split方法 - 因为如果你想保留空条目,则在最后一个标记之后创建一个不存在的条目。

StringReader的输出:

"First Line\r\nSecond Line\r\n\r\n\r\n";
 ^1st          ^2nd           ^3rd^4th   (line)

Split的输出:

"First Line\r\nSecond Line\r\n\r\n\r\n";
 ^1st          ^2nd           ^3rd^4th^5th (token)

考虑这个输入:

"First line\r\n"

它是多少行?一,那是输出:

Split Data:
First Line
[blank line]
StringReader Data:
First Line

所以看来Split就是“问题”(如果有的话)。

Douglas在下面的评论中描述了真正的问题,而"ABC\r\nXYZ""ABC\r\nXYZ\r\n"等输入无法区分。但是,在ReadLine接口的典型用例中,您并不关心这一点。如果你想关心,你需要使用一个较低级别的界面(例如Read)。

答案 1 :(得分:1)

这是预期的行为并记录在案。来自 - http://msdn.microsoft.com/en-us/library/system.io.stringreader.readline.aspx

  

一行被定义为字符序列,后跟换行符(“\ n”),回车符(“\ r”)或回车符后紧跟换行符号(“\ r \ nn “)。返回的字符串不包含终止回车符或换行符。如果已到达字符串的结尾,则返回的值为null。

意味着返回的最后一个值为null,它将省略最后一个换行符。如果您需要在阅读数据中显示,可以通过uisng Environment.NewLine重新申请。

答案 2 :(得分:1)

ReadLine上的每篇文档:

  

一行被定义为字符序列,后跟换行符(“\ n”),回车符(“\ r”)或回车符后紧跟换行符号(“\ r \ nn “)。 返回的字符串不包含终止回车符或换行符。如果到达输入流的末尾,则返回的值为null。

您正在使用依赖Environment.NewLine标记输入流并返回结果的方法。由于这些令牌被排除在结果之外,因此预期行为就是你所看到的。

如果您需要这些字符,最好以块的形式读取文件(使用带缓冲区的标准Read)并自行分解内容。或者,您可以创建自己的Stream实现,根据需要执行任务。