Почему свойство StreamReader.EndOfStream меняет значение BaseStream.Position - PullRequest
3 голосов
/ 29 сентября 2011

Я написал эту маленькую программу, которая читает каждый 5-й символ из Random.txt В random.txt у меня есть одна строка текста: ABCDEFGHIJKLMNOPRST. Я получил ожидаемый результат:

  • Положение А равно 0
  • Позиция F 5
  • Положение К 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;
    }
}

Мой вопрос: почему после строки while (!fp.EndOfStream) BaseStream.Position меняется на 19, например? конец BaseStream. Я ожидал, очевидно, неправильно, что BaseStream.Position останется прежним, когда я позвоню на EndOfStream чек?

Спасибо.

Ответы [ 3 ]

4 голосов
/ 29 сентября 2011

Единственный способ узнать, находится ли 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;
    }
}

(Я не уверен, что делает установка положения за концом файла в этой ситуации, вам может потребоваться добавить проверку для этого.)

2 голосов
/ 29 сентября 2011

Свойство Position базового потока относится к позиции последнего прочитанного байта в буфере , а не к фактической позиции курсора StreamReader.

1 голос
/ 29 сентября 2011

Вы правы, и я в любом случае могу воспроизвести вашу проблему, в соответствии с (MSDN: чтение текста из файла) правильный способ чтения текстового файла с помощью StreamReader следующий, а не ваш(это также всегда закрывает и удаляет поток, используя блок using):

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