为什么StreamReader.EndOfStream属性更改BaseStream.Position值

时间:2011-09-29 12:08:20

标签: c# position streamreader seek

我写了这个小程序,它从Random.txt读取每第5个字符 在random.txt中,我有一行文字:ABCDEFGHIJKLMNOPRST。我得到了预期的结果:

  • A的位置为0
  • F的位置为5
  • K的位置为10
  • P的位置为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;
    }
}

我的问题是,为什么在while (!fp.EndOfStream) BaseStream.Position行更改为19之后,例如BaseStream的结尾。当我打电话BaseStream.Position检查时,我预计EndOfStream会保持不变,显然是错误的吗?

感谢。

3 个答案:

答案 0 :(得分:4)

确定Stream是否在其末尾的唯一方法是实际从中读取内容并检查返回值是否为0.(StreamReader有另一种方式 - 检查其内部缓冲区,但你正确地不要通过调用DiscardBufferedData来实现这一点。)

因此,EndOfStream必须从基本流中读取至少一个字节。而且,由于逐字节读取效率低下,因此读取的内容更多。这就是为什么调用EndOfStream将位置更改为结尾的原因(对于较大的文件,它不会是文件的结尾)。

您似乎实际上不需要使用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;
    }
}

(我不确定在这种情况下设置位置超出文件末尾的位置,你可能需要为此添加一个检查。)

答案 1 :(得分:2)

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

答案 2 :(得分: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);
}