Использование буферов для чтения из файла неизвестного размера - PullRequest
6 голосов
/ 23 июня 2011

Я пытаюсь прочитать блоки из файла, и у меня возникла проблема.

char* inputBuffer = new char[blockSize]
while (inputFile.read(inputBuffer, blockSize)) {
    int i = inputFile.gcount();
//Do stuff
}

Предположим, наш размер блока равен 1024 bytes, а файл - 24,3 KiB. После прочтения 23-го блока останется 0,3 KiB для чтения. Я также хочу прочитать, что 0,3 KiB, на самом деле я использую gcount() позже, чтобы я мог знать, какой объем буфера изменил read(...) (в случае, если он меньше).
Но когда он получает доступ к 24-му блоку, read(...) возвращает значение, такое, что программа не входит в цикл, очевидно, потому что размер оставшихся непрочитанных байтов в файле меньше размера буфера. Что мне делать?

Ответы [ 3 ]

3 голосов
/ 23 июня 2011

Я думаю, что Конрад Рудольф, о котором вы говорите в комментарии к другому ответу, хорошо говорит о проблеме с чтением до конца. Если вы не достигли eof из-за какой-то другой ошибки, вы попали в бесконечный цикл. Поэтому примите его совет, но измените его, чтобы решить проблему, которую вы определили. Один из способов сделать это заключается в следующем:

bool okay=true;
while ( okay ) {
    okay = inputFile.read(inputBuffer, blockSize);
    int i = inputFile.gcount();
    if( i ) {
        //Do stuff
    }
}

Редактировать: Поскольку мой ответ принят, я редактирую его, чтобы он был максимально полезным. Оказывается, мой bool хорошо совершенно не нужен (см. Ответ ferosekhanj). Лучше проверить значение inputFile напрямую, что также имеет то преимущество, что вы можете элегантно избегать входа в цикл, если файл не открывается нормально. Поэтому я думаю, что это каноническое решение этой проблемы;

inputFile.open( "test.txt", ios::binary );
while ( inputFile ) {
    inputFile.read( inputBuffer, blockSize );
    int i = inputFile.gcount();
    if( i ) {
        //Do stuff
    }
}

Теперь, когда вы в последний раз // делаете вещи, я буду меньше, чем blockSize, за исключением случая, когда файл будет кратным байту blockSize.

Ответ Конрада Рудольфа здесь также хорош, у него есть то преимущество, что .gcount () вызывается только один раз, вне цикла, но недостатком является то, что он действительно нуждается в обработке данных, чтобы поместить в отдельный функция, чтобы избежать дублирования.

3 голосов
/ 23 июня 2011

Решение, о котором упоминал Конрад Рудольф, состоит в том, чтобы проверить сам объект потока, поскольку он включает в себя проверку состояния eof и ошибки.InputFile.read () возвращает поток, который является самим inputFile, так что вы можете писать как

while(inputFile.read())

Но это не всегда будет работать.Случай, когда это терпит неудачу - ваш случай.Правильным решением было бы написать, как показано ниже

char* inputBuffer = new char[blockSize]
while (inputFile) 
{
    inputFile.read(inputBuffer, blockSize);
    int count = inputFile.gcount();
    //Access the buffer until count bytes
    //Do stuff
}

Я думаю, что это было решением, которое имел в виду @Konrad Rudolph в своем постеИз моего старого опыта CPP я также сделал бы что-то как выше.

1 голос
/ 23 июня 2011

Но когда он получает доступ к 24-му блоку, read (...) возвращает значение, такое, что программа не входит в цикл, очевидно, потому что размер оставшихся непрочитанных байтов в файле меньше буфераразмер.

Это потому, что ваш цикл не так.Вы должны сделать:

while(!inputFile) {
    std::streamsize numBytes = inputFile.readsome(inputBuffer, blockSize);
//Do stuff
}

Обратите внимание на использование readsome вместо read.

...