C# 如何将文件读入保留CR/LF的字符串?

C# 如何将文件读入保留CR/LF的字符串?,c#,string,file,newline,carriage-return,C#,String,File,Newline,Carriage Return,如果我问“如何将文件读入字符串”这个问题,答案是显而易见的。然而,这里是保留CR/LF的捕获 问题是,File.ReadAllText会删除这些字符StreamReader.ReadToEnd刚刚为我将LF转换为CR,这导致了我在相当明显的代码中存在bug的长期调查;-) 因此,简而言之,如果我有包含foo\n\r\nbar的文件,我希望得到foo\n\r\nbar(即完全相同的内容),而不是foo bar,foobar,或foo\n\nbar。在.Net空间中是否有现成的方法 结果应该始终是单

如果我问“如何将文件读入字符串”这个问题,答案是显而易见的。然而,这里是保留CR/LF的捕获

问题是,
File.ReadAllText
会删除这些字符
StreamReader.ReadToEnd
刚刚为我将LF转换为CR,这导致了我在相当明显的代码中存在bug的长期调查;-)

因此,简而言之,如果我有包含
foo\n\r\nbar
的文件,我希望得到
foo\n\r\nbar
(即完全相同的内容),而不是
foo bar
foobar
,或
foo\n\nbar
。在.Net空间中是否有现成的方法

结果应该始终是单个字符串,包含整个文件

结果应该始终是单个字符串,包含整个文件

它需要两跳。第一个是File.ReadAllBytes(),用于获取文件中的所有字节。它不试图翻译任何东西,而是获取文件中的原始数据,因此古怪的行尾会保持原样


但那是字节,你要的是字符串。因此,第二步是应用Encoding.GetString()将字节转换为字符串。您必须做的一件事是选择正确的编码类,该类与编写文件的程序使用的编码相匹配。如果文件包含
\n\r\n
序列,并且您没有记录有关该文件的任何其他内容,那么最好使用Encoding.Default。根据需要进行调整。

您确定这些方法是剥离角色的罪魁祸首吗

我试着写一个快速测试
StreamReader.ReadToEnd
保留所有换行符

string str = "foo\n\r\nbar";
using (Stream ms = new MemoryStream(Encoding.ASCII.GetBytes(str)))
using (StreamReader sr = new StreamReader(ms, Encoding.UTF8))
{
    string str2 = sr.ReadToEnd();
    Console.WriteLine(string.Join(",", str2.Select(c => ((int)c))));
}

// Output: 102,111,111,10,13,10,98,97,114
//           f   o   o \n \r \n  b  a   r
在写入和读取临时文件时,可以获得相同的结果:

string str = "foo\n\r\nbar";
string temp = Path.GetTempFileName();
File.WriteAllText(temp, str);
string str2 = File.ReadAllText(temp);
Console.WriteLine(string.Join(",", str2.Select(c => ((int)c))));

您的换行符似乎在别处丢失了。

您可以使用
file.ReadAllLines
读取文件内容,这将返回一个行数组。然后使用
String.Join
使用分隔符将行合并在一起

string[] lines = File.ReadAllLines(@"C:\Users\User\file.txt");
string allLines = String.Join("\r\n", lines);
请注意,这将丢失实际行终止符字符的精度。例如,如果行仅以
\n
\r
结尾,则生成的字符串
所有行
将替换为
\r\n
行终止符


当然,还有其他方法可以在不丢失真正的EOL终止符的情况下实现这一点,但是,
ReadAllLines
很方便,因为它可以自己检测多种类型的文本编码,并且它也占用很少的代码行。

这段代码将保留LR和CR

string r = File.ReadAllText(@".\TestData\TR120119.TRX", Encoding.ASCII);

ReadAllText不返回回车

此方法打开一个文件,读取文件的每一行,然后将每一行添加为字符串的元素。然后关闭该文件。行定义为一系列字符,后跟回车符('\r')、换行符('\n')或紧跟换行符的回车符结果字符串不包含终止回车和/或换行符


从MSDN-

来看,这与公认的答案类似,但希望更切题
sr.ReadToEnd()
将读取所需的字节:

string myFilePath = @"C:\temp\somefile.txt";
string myEvents = String.Empty;

FileStream fs = new FileStream(myFilePath, FileMode.Open);
StreamReader sr = new StreamReader(fs);
myEvents = sr.ReadToEnd();
sr.Close();
fs.Close();
您甚至可以使用语句在级联的
中执行这些操作。但我想描述一下,您首先写入该文件的方式将如何决定如何从
myEvents
字符串中读取内容,这可能就是问题所在。我这样写到我的文件:

using System.Reflection;
using System.IO;

private static void RecordEvents(string someEvent)
{
    string folderLoc = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    if (!folderLoc.EndsWith(@"\")) folderLoc += @"\";
    folderLoc = folderLoc.Replace(@"\\", @"\"); // replace double-slashes with single slashes
    string myFilePath = folderLoc + "myEventFile.txt";

    if (!File.Exists(myFilePath))
        File.Create(myFilePath).Close(); // must .Close() since will conflict with opening FileStream, below

    FileStream fs = new FileStream(myFilePath, FileMode.Append);
    StreamWriter sr = new StreamWriter(fs);
    sr.Write(someEvent + Environment.NewLine);
    sr.Close();
    fs.Close();
}
然后我可以使用上面的代码来获取内容的字符串。因为我要进一步查找单个字符串,所以我将此代码放在该代码之后,放在那里:

if (myEvents != String.Empty) // we have something
{
    // (char)2660 is ♠  -- I could have chosen any delimiter I did not
    // expect to find in my text
    myEvents = myEvents.Replace(Environment.NewLine, ((char)2660).ToString());
    string[] eventArray = myEvents.Split((char)2660);
    foreach (string s in eventArray)
    {
        if (!String.IsNullOrEmpty(s))
            // do whatever with the individual strings from your file
    }
}

这很有效。所以我知道
myEvents
必须保留
环境。换行符
字符,因为我可以用
(char)2660
替换它,并使用该字符对该字符串执行
.Split()
分割成单独的段。

为什么不将其作为
字节[]
处理呢?File.ReadAllBytes等不确定。。但是,
\n\r\n
是换行-回车-换行。所以当它读到。。很可能它只是在一开始就删除了悬挂的换行符,而支持回车换行符组合。不过,我并不是.NET StreamReader内部工作原理的专家:(@marcGravel,类似于
newstring(System.IO.File.ReadAllBytes(filename.Select)(b=>(char)b.ToArray())
?仍然有
\n
被转换的地方,无论如何,我将不得不进一步调查它。标准例程的非标准要求不起作用,不是很奇怪吗?你说的是文本,它按照你说的做了。我不相信编码的选择会导致换行序列被改变。如果你还没有告诉我,那就假设得很高EBCDIC。不是重点,ASCII控制字符之间的内容很重要。这是重点。如果OP使用任何ASCII兼容编码(包括UTF-8),则控制字符之间的内容无关紧要;多字节序列不能包含值10或13。是的,使用非ASCII兼容编码,如EBCDIC(甚至UTF-16)会引入一系列新的考虑因素,但我认为OP会提到它,如果它们是的话。对于这个问题,这是我在代码中隐藏的错误,我喜欢你的解释和步骤描述——非常感谢!天哪,你是对的,感谢示例代码对其进行了更彻底的测试,我把阅读文本并显示结果后立即出现的代码让我感到困惑。对此我很抱歉,但仍有很多东西需要学习。很高兴您找到了原因:-)不幸的是,正如所有其他示例、我自己的测试和.Net参考代码所示,这不是真的。