如何知道文本文件是否以回车结束?

时间:2017-01-14 10:37:20

标签: c# encoding text-files newline streamreader

我必须处理一个文本文件并检查它是否以回车符结束。

我必须阅读整个内容,进行一些更改并将其重新写入目标文件,保持与原始格式完全相同的格式。这就是问题所在:我不知道原始文件最后是否包含换行符。

我已经尝试过了:

  • StreamReader.ReadLine()方法,但返回的字符串不包含终止回车符和/或换行符。
  • ReadToEnd()方法也可以是一个解决方案,但我想知道非常大的文件时的性能。解决方案必须高效。
  • 获取最后2个字符并检查它们是否等于“\ r \ n”可能会解决它,但我必须处理大量编码,而且似乎几乎不可能得到它们。

如何有效地阅读文件的所有文本并确定它是否以换行符结束?

2 个答案:

答案 0 :(得分:6)

通过ReadLine()读取文件后,您可以在文件结尾前回溯两个字符,并将这些字符与CR-LF进行比较:

string s;
using (StreamReader sr = new StreamReader(@"C:\Users\User1\Desktop\a.txt", encoding: System.Text.Encoding.UTF8))
{
    while (!sr.EndOfStream)
    {
        s = sr.ReadLine();
        //process the line we read...
    }

    //if (sr.BaseStream.Length >= 2) { //ensure file is not so small

    //back 2 bytes from end of file
    sr.BaseStream.Seek(-2, SeekOrigin.End);

    int s1 = sr.Read(); //read the char before last
    int s2 = sr.Read(); //read the last char 
    if (s2 == 10) //file is end with CR-LF or LF ... (CR=13, LF=10)
    {
        if (s1 == 13) { } //file is end with CR-LF (Windows EOL format)
        else { } //file is end with just LF, (UNIX/OSX format)
    }

}

答案 1 :(得分:2)

因此,您正在处理文本文件,这意味着您需要阅读所有文本,并希望保留任何换行符,即使在文件末尾也是如此。

您已正确地断定ReadLine()吃掉了那些,即使文件没有以一个结尾。事实上,当文件以一个文件结尾时,ReadLine()会吃掉最后一个回车符(StreamReader.EndOfStream在读取倒数第二行后为trueReadAllText() also eats the last newline。鉴于您可能正在处理大型文件,您也不希望立即读取内存中的整个文件。

您也不能只比较文件的最后两个字节,因为有些编码使用多个字节来编码字符,例如UTF-16。因此,您需要读取可识别编码的文件。 StreamReader就是这么做的。

因此,解决方案是创建自己的ReadLine()版本,其中包含最后的换行符:

public static class StreamReaderExtensions
{
    public static string ReadLineWithNewLine(this StreamReader reader)
    {
        var builder = new StringBuilder();

        while (!reader.EndOfStream)
        {
            int c = reader.Read();

            builder.Append((char) c);
            if (c == 10)
            {
                break;
            }
        }

        return builder.ToString();
    }
}

然后,您可以检查上一个返回的行是否以\n结尾:

string line = "";

using (var stream = new StreamReader(@"D:\Temp\NewlineAtEnd.txt"))
{
    while (!stream.EndOfStream)
    {
        line = stream.ReadLineWithNewLine();
        Console.Write(line);
    }
}

Console.WriteLine();

if (line.EndsWith("\n"))
{
    Console.WriteLine("Newline at end of file");
}
else
{
    Console.WriteLine("No newline at end of file");
}

尽管StreamReader经过了大量优化,但我无法保证每次阅读一个字符的性能。与ReadLine()相比,使用两个相同的100 MB文本文件进行快速测试显示出相当大的减速(~1800 vs~400 ms)。

此方法确实保留了原始行结尾,这意味着您可以使用此扩展方法返回的字符串安全地重写文件,而不会将所有\n更改为\r\n,反之亦然。