2013-08-04 82 views
0

我有一個奇怪的情況,我不明白與我正在發送到文件的換行符'\n'有關。根據TextWriterEnvironmentNewLine屬性,換行似乎不被處理。此代碼演示:Environment.NewLine和TextWriter.NewLine屬性有什麼用處

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(); 

當我運行此控制檯輸出

當我看着我的十六進制模式文件獲取:

00000000h: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方法沒有考慮到這一點,有沒有一個,但有兩個NewLine屬性的用途?這些是爲了什麼?

回答

0

所有換行符轉義爲\ n的字符串是單字符的ASCII換行字符(0x0A)(而不是Windows換行符0D0A),並輸出到除非編程人員採取某些明確的步驟將字符串內的這些字符串轉換爲0D0A格式,否則作爲0x0A流。

TextWriter.NewLine屬性僅用於像WriteLine這樣的方法,並控制作爲調用一部分附加的隱式換行符的格式。

Environment.NewLineTextWriter.NewLine之間的區別在於Environment.NewLine是隻讀的,僅供程序員查詢。 (這是從Java的不同,例如,在那裏你可以寫的用TextWriter.NewLine時更改「全系統的」換行格式與System.setProperty("line.separator", x);

默認在C#中,你可以修改隱含換行的格式,它被初始化爲Environment.NewLine 。當使用讀取行的TextReader方法時,沒有TextReader.NewLine屬性。讀取器的隱含換行行爲是在任何0x0A,0x0D或0D0A處中斷。正如rene指出的,原始問題可以通過編寫來解決:

sw.Write("1\uf0f1\n2\ue0e1\n3\ud0d1\n".Replace("\n", Environment.NewLine)); 
1

如果選擇通過將\ n發送給Streamwriter來生成'linebreaks'你自己,那麼框架將無法干預該行爲。如果您希望框架遵循NewLine屬性,請使用Writer的WriteLine方法並設置Writer的Ne​​wLine屬性。

適應您的代碼如下所示:

sw.NewLine = Environment.NewLine; // StreamWriter uses \r\n by default 

sw.WriteLine("1\uf0f1") 
sw.WriteLine("2\ue0e1"); 
sw.WriteLine("3\ud0d1"); 

或者有一個自定義的StreamWriter重寫Write方法:

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)); 
+0

有沒有賭注這樣做的方式不涉及製作三個方法調用而不是一個的開銷?據我瞭解,'WriteLine'會考慮到'TextWriter.NewLine'屬性。我仍然留下了「Environment.NewLine」的目的是什麼。 – Mishax

+0

爲了幫助消除讀者對上述評論的任何誤解:WriteLine(X)只需調用Write(X),然後調用WriteLine(),而WriteLine()又簡單地追加TextWriter.NewLine。換句話說,TextWriter.NewLine簡單地決定了每個WriteLine(X)調用結束時TextWriter附加的內容。而已。它完全按照您發送的內容準確發送您發送的內容。 – AnorZaken

0

如果您隱式使用,如調用WriteLine方法或顯式地使用Write(String.C oncat(「Hello」,Environment.NewLine),你會得到爲你的環境定義的行尾字符。如果你不使用它並使用'\ n'或者甚至'$',那麼你說的是不管我在什麼環境下,線條都會像我說的那樣結束。如果你想比較行爲,寫一點代碼,並運行它在Windows和Linux下(單聲道)

+0

啊!你是說Environment.NewLine的目的主要是讓程序員使用,而TextWriter.NewLine是爲運行時使用的嗎?那是有道理的。我不知道我爲什麼擁有這兩個屬性。 – Mishax

+0

不知道TextWriter有它自己的,但我懷疑它默認爲Environment。當一個特定的文件來自或針對不同的環境時,方便的設置它,然後您的代碼的其餘部分是不可知的。 –

4

程序員有很長的歷史而不是同意如何編寫文本時,它被寫入文件。 ASCII和Unicode有助於在一定程度上平衡巴別塔。但是什麼字符表示一條線的結尾從來沒有達成一致。

  • Windows使用回車+換行控制代碼。 C#代碼中的"\r\n"
  • Unix風格在C#代碼中只使用一個換行控制代碼'\n'
  • 蘋果歷史上只使用C#代碼中的單個回車控制代碼'\r'

.NET需要與所有這些不兼容的選擇兼容。因此它添加了Environment.NewLine屬性,它具有操作系統的默認行結束順序。注意如何在Unix和Apple機器上使用Mono或Silverlight運行.NET代碼。

抽象TextWriter類需要知道使用什麼序列,因爲它寫入文本文件。所以它有一個NewLine屬性,它的默認值和Environment.NewLine一樣。你幾乎總是使用它,但是如果你需要創建一個由另一個操作系統上的程序讀取的文本文件,你可能需要改變它。

您在程序中犯的錯誤是您的硬編碼行終止符。你在字符串中使用了'\ n'。這完全繞過了.NET屬性,您將只能看到文本文件中的單行換行控制代碼。 0x0A是換行符。您的控制檯輸出顯示「2」,因爲它只顯示NewLine屬性的字符串長度。 Windows上的「\ r \ n」是2。

使用.NET性能的最簡單的方法是使用的WriteLine()的寫入,而不是():

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); 
+0

你的知識令人驚訝地無與倫比。 – butterbox

+1

我真心希望它不是一個驚喜:) –

相關問題