我怎么知道文本文件是否以回车符 return 结尾?
How can I know if a text file ends with carriage return or not?
我必须处理一个文本文件并检查它是否以回车符结尾 return。
我必须阅读全部内容,进行一些更改并将其重新写入目标文件,并保持与原始格式完全相同的格式。问题是:我不知道原始文件最后是否包含换行符。
我已经试过了:
- StreamReader.ReadLine() 方法,但 returned 的字符串不包含终止回车 return and/or 换行。
- ReadToEnd() 方法也是一种解决方案,但我想知道在处理非常大的文件时的性能。解决方案必须高效。
- 获取最后 2 个字符并检查它们是否等于“\r\n”可能会解决问题,但我必须处理很多编码,而且似乎几乎不可能获取它们。
如何有效地读取文件的所有文本并确定它是否以换行符结尾?
通过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)
}
}
所以你正在处理一个文本文件,这意味着你需要读取所有文本,并希望保留任何换行符,即使在文件末尾也是如此。
您正确地得出结论 ReadLine()
吃掉了那些文件,即使文件不以 one 结尾。事实上,当文件以 1 结尾时,ReadLine()
吃掉了最后一个 return(StreamReader.EndOfStream
在读取倒数第二行后是 true
)。 ReadAllText()
also eats the last newline。考虑到您可能要处理大文件,您也不想一次读取内存中的整个文件。
你也不能只比较文件的最后两个字节,因为有些编码使用多个字节来编码一个字符,例如UTF-16。所以你需要阅读文件encoding-aware。 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();
}
}
然后你可以检查最后一个 returned 行是否以 \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()
(~1800 vs ~400 毫秒)相比,使用两个相等的 100 MB 文本文件进行的快速测试显示速度明显下降。
虽然这种方法确实保留了原始行尾,这意味着您可以使用通过这种扩展方法 return 编辑的字符串安全地重写文件,而无需将所有 \n
更改为 \r\n
或反之亦然。
我必须处理一个文本文件并检查它是否以回车符结尾 return。
我必须阅读全部内容,进行一些更改并将其重新写入目标文件,并保持与原始格式完全相同的格式。问题是:我不知道原始文件最后是否包含换行符。
我已经试过了:
- StreamReader.ReadLine() 方法,但 returned 的字符串不包含终止回车 return and/or 换行。
- ReadToEnd() 方法也是一种解决方案,但我想知道在处理非常大的文件时的性能。解决方案必须高效。
- 获取最后 2 个字符并检查它们是否等于“\r\n”可能会解决问题,但我必须处理很多编码,而且似乎几乎不可能获取它们。
如何有效地读取文件的所有文本并确定它是否以换行符结尾?
通过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)
}
}
所以你正在处理一个文本文件,这意味着你需要读取所有文本,并希望保留任何换行符,即使在文件末尾也是如此。
您正确地得出结论 ReadLine()
吃掉了那些文件,即使文件不以 one 结尾。事实上,当文件以 1 结尾时,ReadLine()
吃掉了最后一个 return(StreamReader.EndOfStream
在读取倒数第二行后是 true
)。 ReadAllText()
also eats the last newline。考虑到您可能要处理大文件,您也不想一次读取内存中的整个文件。
你也不能只比较文件的最后两个字节,因为有些编码使用多个字节来编码一个字符,例如UTF-16。所以你需要阅读文件encoding-aware。 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();
}
}
然后你可以检查最后一个 returned 行是否以 \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()
(~1800 vs ~400 毫秒)相比,使用两个相等的 100 MB 文本文件进行的快速测试显示速度明显下降。
虽然这种方法确实保留了原始行尾,这意味着您可以使用通过这种扩展方法 return 编辑的字符串安全地重写文件,而无需将所有 \n
更改为 \r\n
或反之亦然。