2014-12-04 123 views
0

我有一個StreamWriter在我讀取它的同時打開我的文件,這似乎是導致問題的原因(這是更大的一組代碼中的一個較小片段,只是以說明我的問題):StreamWriter正在將BOM字符65279附加到文件結尾

static void Main(string[] args) 
{ 
    for (int i = 0; i < 3; i++) 
    { 
     using (FileStream stream = new FileStream("file.txt", FileMode.OpenOrCreate)) 
     using (StreamReader reader = new StreamReader(stream, Encoding.UTF8, false, 0x1000, true)) 
     using (StreamWriter writer = new StreamWriter(stream, Encoding.UTF8, 0x1000, true)) 
     { 
      Console.WriteLine("Read \"" + reader.ReadToEnd() + "\" from the file."); 
     } 
    } 
    Console.ReadLine(); 
} 

上面的代碼將輸出:

Read "" from the file. 
Read "" from the file. 
Read "?" from the file. 

如果文件已經包含了一些文字,筆者將BOM到最後追加儘管從未被稱爲寫任何東西:

Read "TEXT" from the file. 
Read "TEXT?" from the file. 
Read "TEXT??" from the file. 

它爲什麼會表現出這種行爲?

+0

可能的重複[如何忽略字符串比較中的UTF-8字節順序標記?](http://stackoverflow.com/questions/2915182/how-do-i-ignore-the-utf-8-字節順序標記在字符串比較) – grovesNL 2014-12-04 16:35:39

+0

@grovesNL這是關於StreamReader,而不是關於GetString,這些答案不幫助我。 – Alexandru 2014-12-04 16:41:51

+1

@grovesNL即使它的BOM值我會很驚訝地看到**在最後**而不是開始... – 2014-12-04 16:41:59

回答

3

正如我以前在關於字節順序標記的評論中暗示的,您試圖避免在StreamWriter中添加字節順序標記。這是基於您正在使用的編碼器。

例如,嘗試不用寫字節順序標記創建自己的編碼器:

static void Main(string[] args) 
{ 
    for (int i = 0; i < 3; i++) 
    { 
     using (FileStream stream = new FileStream("file.txt", FileMode.OpenOrCreate)) 
     using (StreamReader reader = new StreamReader(stream, Encoding.UTF8, true, 0x1000, true)) 
     using (StreamWriter writer = new StreamWriter(stream, new UTF8Encoding(false), 0x1000, true)) 
     { 
      Console.WriteLine("Read \"" + reader.ReadToEnd() + "\" from the file."); 
     } 
    } 
    Console.ReadLine(); 
} 

使用new UTF8Encoding(false)爲您的UTF8編碼器,編碼器明確指示不要使用Unicode字節順序標記。這在MSDN entry for the UTF8Encoding constructor中描述。

+0

是的,這是有效的。我想我正在使用StreamReader讀取數據流的末尾...然後作者將被丟棄,並且在處置時,我想流處理器認爲它在流的起始處,因爲它沒有被調用,所以追加BOM標誌爲UTF8,這是不智能的,因爲它應該讀取FileStream的位置以知道它在哪裏。如果沒有這些標誌,您只需要知道編碼就可以從文件中打開並讀取。我對嗎? – Alexandru 2014-12-04 17:35:09

+1

@亞歷山大:是的,在你的'Console.WriteLine'調用之前寫入你的'writer'時,它會更清楚地表達出來。只要嘗試添加'writer.Write(「test」)'並觀察如何添加字節順序標記。 – grovesNL 2014-12-04 17:42:50

1

好吧。我認爲即使你不寫任何東西,作者也想寫字節順序標記。您將流位置移動到流結束位置,因此當您處理寫入器時 - 它會將字節順序標記刷新到流尾。

試試這個代碼

static void Main(string[] args) 
    { 
     for (int i = 0; i < 3; i++) 
     { 
      using (FileStream stream = new FileStream("sample.txt", FileMode.OpenOrCreate)) 
      using (StreamReader reader = new StreamReader(stream, Encoding.UTF8, false, 0x1000, true)) 
      using (StreamWriter writer = new StreamWriter(stream, Encoding.UTF8, 0x1000, true)) 
      { 
       writer.Flush(); 
       Console.WriteLine("Read \"" + reader.ReadToEnd() + "\" from the file."); 
      } 
     } 
     Console.ReadLine(); 
    } 

你會看到預期的行爲,不 '?'符號。

+0

我希望我能接受兩個答案,但樹叢擊敗了你。人們:如果你閱讀這個,這也是一個非常可靠的方法。 Taukita,這會導致作者始終確保它在開始時標記文件。 – Alexandru 2014-12-04 17:46:39

+0

這工作真的很棒。我在我正在寫的庫中採用了這種方法,因爲這給了你一個新文件開始時的正確的BOM標籤。 – Alexandru 2014-12-04 19:00:23