2011-09-29 132 views
3

我寫了這個小程序,它從Random.txt中讀取每第5個字符 在random.txt中,我有一行文本:ABCDEFGHIJKLMNOPRST。我得到了預期的結果:爲什麼StreamReader.EndOfStream屬性更改BaseStream.Position值

  • A的位置爲0
  • 的F
  • 位置是K的5
  • 位置是P的10
  • 位置是15

這裏是代碼:

static void Main(string[] args) 
{ 
    StreamReader fp; 
    int n; 
    fp = new StreamReader("d:\\RANDOM.txt"); 
    long previousBSposition = fp.BaseStream.Position; 
    //In this point BaseStream.Position is 0, as expected 
    n = 0; 

    while (!fp.EndOfStream) 
    { 
     //After !fp.EndOfStream were executed, BaseStream.Position is changed to 19, 
     //so I have to reset it to a previous position :S 
     fp.BaseStream.Seek(previousBSposition, SeekOrigin.Begin); 
     Console.WriteLine("Position of " + Convert.ToChar(fp.Read()) + " is " + fp.BaseStream.Position); 
     n = n + 5; 
     fp.DiscardBufferedData(); 
     fp.BaseStream.Seek(n, SeekOrigin.Begin); 
     previousBSposition = fp.BaseStream.Position; 
    } 
} 

我的問題是,爲什麼行後BaseStream.Position變爲19,例如結尾BaseStream。我的預期,顯然是錯誤的,是BaseStream.Position將保持不變,當我打電話EndOfStream檢查?

謝謝。

+3

StreamReader的內部有一個緩衝,讓解碼字節的文本。使用它的任何方法都會導致它從文件流中汲取字節。其頭寸價值將不可預測。 –

+0

@HansPassant,我認爲這是'在發佈代碼()調用'DiscardBufferedData的原因。 – svick

+0

@HansPassant,是的,我打我上面的代碼,我注意到的StreamReader的Read()方法也導致在某些情況下BaseStream.Position的變化,所以它是不可預測的。 – vldmrrdjcc

回答

4

THRE唯一途徑找出Stream是否處於其到底是要真正從中讀到的東西,並檢查返回值是否爲0(StreamReader有另外一種方法–檢查其內部緩衝區,但你正確地穿上」不要讓它通過調用DiscardBufferedData來完成。)

因此,EndOfStream必須從基本流讀取至少一個字節。由於逐字節讀取效率低,因此讀取更多。這就是爲什麼在調用EndOfStream改變位置到結束的原因(這woulnd't是文件的更大的文件末尾)。

看來你並不真正需要使用StreamReader,所以你應該使用Stream(或專門FileStream)直接:

using (Stream fp = new FileStream(@"d:\RANDOM.txt", FileMode.Open)) 
{ 
    int n = 0; 

    while (true) 
    { 
     int read = fp.ReadByte(); 
     if (read == -1) 
      break; 

     char c = (char)read; 
     Console.WriteLine("Position of {0} is {1}.", c, fp.Position); 
     n += 5; 
     fp.Position = n; 
    } 
} 

(我不知道是什麼超出設定的結束位置文件就在這種情況下,你可能需要添加一個檢查。)

+0

我想我明白了。還有一個問題:StreamReader不會緩衝整個流,而是緩衝整個流的一部分,所以在一些不可預知的時刻,當他需要更多數據時,它會從BaseStream中讀取數據?我收到了嗎? – vldmrrdjcc

+0

非常,是的。除了它不是不可預測的。當緩衝區爲空且您需要讀取一些字節時,可隨時讀取基本流。特別是在你發佈的代碼中,因爲在丟棄之前你從緩衝區讀取的內容不多。 – svick

+0

看來,EndOfStream正好讀取了1024個下一個字節。如果在EndOfStream調用之後使用DiscardBufferedData,然後使用ReadLine,則將獲得1024個字符後面的部分行。 –

1

你是對的,我也可以重現你的問題,無論如何根據(MSDN: Read Text from a File)用StreamReader讀取文本文件的正確方法是以下,而不是你的(這也總是關閉和配置流通過使用使用塊):

try 
{ 
    // Create an instance of StreamReader to read from a file. 
    // The using statement also closes the StreamReader. 
    using (StreamReader sr = new StreamReader("TestFile.txt")) 
    { 
     String line; 
     // Read and display lines from the file until the end of 
     // the file is reached. 
     while ((line = sr.ReadLine()) != null) 
     { 
      Console.WriteLine(line); 
     } 
    } 
} 
catch (Exception e) 
{ 
    // Let the user know what went wrong. 
    Console.WriteLine("The file could not be read:"); 
    Console.WriteLine(e.Message); 
} 
+0

如果你把一個破發點到線,而(!fp.EndOfStream),你會看到BaseStream.Position的是,行權後的變化,Console.WriteLine(前... – vldmrrdjcc

+0

你爲什麼不只是簡單的閱讀位置,而不是BaseStream.Position? –

+0

StreamReader沒有自己的Position屬性:S – vldmrrdjcc

2

的基本流的屬性Position是指最後的讀取字節的在緩衝器,而不是StreamReader的的光標的實際位置的位置。

+1

儘管文檔沒有清楚地說明這一點,但「位置」確實指的是字節,而不是緩衝區。我不確定那會是甚麼意思。 – svick