简体   繁体   中英

Why StreamReader.EndOfStream property change the BaseStream.Position value

I wrote this small program which reads every 5th character from Random.txt In random.txt I have one line of text: ABCDEFGHIJKLMNOPRST. I got the expected result:

  • Position of A is 0
  • Position of F is 5
  • Position of K is 10
  • Position of P is 15

Here is the code:

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;
    }
}

My question is, why after line while (!fp.EndOfStream) BaseStream.Position is changed to 19, eg end of a BaseStream . I expected, obviously wrong, that BaseStream.Position will stay the same when I call EndOfStream check?

Thanks.

Thre only certain way to find out whether a Stream is at its end is to actually read something from it and check whether the return value is 0. ( StreamReader has another way – checking its internal buffer, but you correctly don't let it do that by calling DiscardBufferedData .)

So, EndOfStream has to read at least one byte from the base stream. And since reading byte by byte is inefficient, it reads more. That's the reason why the call to EndOfStream changes the position to the end (it woulnd't be the end of file for bigger files).

It seems you don't actually need to use StreamReader , so you should use Stream (or specifically FileStream ) directly:

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;
    }
}

(I'm not sure what does setting the position beyond the end of file do in this situation, you may need to add a check for that.)

基本流的Position属性是指缓冲区中最后读取字节的位置,而不是StreamReader光标的实际位置。

You are right and I could reproduce your issue as well, anyway according to (MSDN: Read Text from a File) the proper way to read a text file with a StreamReader is the following, not yours (this also always closes and disposes the stream by using a using block):

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM