C# Environment.NewLine和TextWriter.NewLine属性的用途是什么
我有一个奇怪的情况,我不理解与我要发送到文件的新行“\n”有关的情况。根据TextWriter和Environment的换行符属性,似乎不会对换行符进行处理。此代码演示:C# Environment.NewLine和TextWriter.NewLine属性的用途是什么,c#,io,newline,C#,Io,Newline,我有一个奇怪的情况,我不理解与我要发送到文件的新行“\n”有关的情况。根据TextWriter和Environment的换行符属性,似乎不会对换行符进行处理。此代码演示: String baseDir = Environment.GetEnvironmentVariable("USERPROFILE") + '\\'; String fileName = baseDir + "deleteme5.txt"; FileInfo fi = new FileInfo(fileName); fi.Del
String baseDir = Environment.GetEnvironmentVariable("USERPROFILE") + '\\';
String fileName = baseDir + "deleteme5.txt";
FileInfo fi = new FileInfo(fileName);
fi.Delete();
FileStream fw = new FileStream(fileName, FileMode.CreateNew, FileAccess.Write);
StreamWriter sw = new StreamWriter(fw);
Console.WriteLine(Environment.NewLine.Length);
Console.WriteLine(sw.NewLine.Length);
sw.Write("1\uf0f1\n2\ue0e1\n3\ud0d1\n");
sw.Flush();
sw.Close();
当我运行此命令时,控制台输出为
二,
二,
当我以十六进制模式查看文件时,我得到:
00000000小时:31 EF 83 B1 0A 32 EE 83 A1 0A 33 ED 83 91 0A;
1ïƒ.2îƒ.3ƒ”
显然,API显示了两个字符,当您查看文件时,只有一个字符。现在,当我查看TextWriter中Write方法的描述时,它表明Write方法不会用NewLine属性替换0A。如果Write方法没有考虑到这一点,那么不是一个而是两个换行符属性又有什么用呢?这些东西是干什么用的?如果选择通过发送给streamwriter来生成“换行符”,则框架将无法与之干涉。如果希望框架支持换行符属性,请使用writer的WriteLine方法并设置writer的换行符属性 对代码进行如下调整:
sw.NewLine = Environment.NewLine; // StreamWriter uses \r\n by default
sw.WriteLine("1\uf0f1")
sw.WriteLine("2\ue0e1");
sw.WriteLine("3\ud0d1");
或具有覆盖写入方法的自定义StreamWriter:
public class MyStreamWriter:StreamWriter
{
public MyStreamWriter(Stream s):base(s)
{
}
public override void Write(string s)
{
base.Write(s.Replace("\n",Environment.NewLine));
}
}
或者,如果您只想处理一行:
sw.Write("1\uf0f1\n2\ue0e1\n3\ud0d1\n".Replace("\n", Environment.NewLine));
如果在调用WriteLine方法时隐式使用,或在WriteString.Concatherlo、Environment.NewLine中显式使用,则会得到为环境定义的行尾字符。如果您不使用它,并使用“\n”甚至“$”,那么您的意思是,无论我在什么环境中,行都会像我所说的那样结束。如果您想比较行为,请编写一段代码并在windows和linux mono下运行。程序员长期以来一直不同意在将文本写入文件时如何对其进行编码。ASCII和Unicode在一定程度上帮助了巴别塔的升级。但是,什么字符表示一行的结尾从未达成一致 Windows使用回车+换行控制代码\r\n在C代码中。 Unix版本只使用一行提要控制代码,C代码中的“\n”。 苹果历史上只使用一个回车控制代码,C代码中的“\r”。 NET需要与所有这些不兼容的选择兼容。因此,它添加了Environment.NewLine属性,它具有操作系统的默认行结束顺序。请注意如何使用Mono或Silverlight在Unix和Apple计算机上运行.NET代码 抽象TextWriter类需要知道使用什么序列,因为它编写文本文件。因此它有一个换行符属性,其默认值与Environment.NewLine相同。您几乎总是使用它,但是如果您需要创建一个文本文件供另一个操作系统上的程序读取,您可能需要更改它 您在程序中犯的错误是您硬编码了行终止符。您在字符串中使用了“\n”。这完全绕过了.NET属性,您只能在文本文件中看到单行提要控制代码。0x0A是一个换行符。控制台输出显示2,因为它只显示换行符属性的字符串长度。这是Windows上的2,用于\r\n 使用.NET属性的最简单方法是使用WriteLine而不是Write:
sw.WriteLine("1\uf0f1");
sw.WriteLine("2\ue0e1");
sw.WriteLine("3\ud0d1");
这也使得您的代码可读性很好,在运行时不会慢。如果要保留一行,则可以使用复合格式:
sw.Write("1\uf0f1{0}2\ue0e1{0}3\ud0d1{0}", Environment.NewLine);
字符串中所有转义为\n的换行符都是单字符ASCII换行符0x0A而不是Windows换行符0D0A,并以0x0A的形式输出到写入程序中的流,除非程序员采取明确步骤将字符串中的换行符转换为格式0D0A TextWriter.NewLine属性仅由WriteLine等方法使用,并控制作为调用一部分追加的隐式换行符的格式 Environment.NewLine和TextWriter.NewLine之间的区别在于Environment.NewLine是只读的,只能由程序员查询。这与Java不同,例如,在Java中,您可以使用system.setPropertyline.separator,x更改系统范围的换行格式默认值 在C中,您可以在使用TextWriter.newline(初始化为Environment.newline)编写时修改隐式换行符的格式。使用读取行的TextReader方法时,没有TextReader.NewLine属性。读取器的隐式换行行为是在任何0x0A、0x0D或0D0A处中断 正如rene所指出的,最初的问题可以通过书面形式解决:
sw.Write("1\uf0f1\n2\ue0e1\n3\ud0d1\n".Replace("\n", Environment.NewLine));
有没有更好的方法可以做到这一点,而不需要进行三次而不是一次方法调用的开销?据我所知,WriteLine将考虑TextWriter.NewLine属性。我仍然有一个问题:Environment.NewLine.的目的是什么?为了帮助别人消除误解,请阅读
对上面的注释进行注释:WriteLineX只调用WriteX,然后调用WriteLine,然后再简单地追加TextWriter.NewLine。换句话说,TextWriter.NewLine只确定TextWriter在每个WriteLineX调用末尾追加的内容。没别的了。它写的东西和你发的一模一样。啊!你是说Environment.NewLine主要供程序员使用,TextWriter.NewLine主要供运行时使用?这是有道理的。我不知道为什么我有这两个属性。我不知道TextWriter有自己的属性,但我怀疑它默认为Environment的。当一个特定文件来自或用于不同的环境时,设置它,然后您的其余代码就不可知了。您的知识令人惊讶地无与伦比。我真诚地希望这不是一个意外: