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, e.g. 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.)
The base stream's Position
property refers to the position of the last read byte in the buffer, not the actual position of the StreamReader's cursor.
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);
}
精彩评论