Использование fseek для возврата
Вопрос
Использует fseek
вернуть персонажа назад fscanf
операции надежны?
Например, если я только что fscanf
-ed 10 символов, но я хотел бы вернуться к 10 символам, могу ли я просто fseek(infile, -10, SEEK_CUR)
?
В большинстве ситуаций это работает, но у меня, похоже, проблемы с персонажем. ^M
.Видимо fseek
регистрирует его как символ, но fscanf
не регистрирует его, поэтому в моем предыдущем примере блок из 10 символов содержит ^M
потребует fseek(infile, -11, SEEK_CUR)
вместо. fseek(infile, -10, SEEK_CUR)
сократит его на 1 символ.
Почему это так?
Редактировать:я использовал fopen
в текстовом режиме
Решение
Вы видите разницу между «текстовым» и «двоичным» файлом.Когда файл открывается в текстовом режиме (во втором аргументе fopen нет буквы «b»), библиотека stdio может (действительно должна) интерпретировать содержимое файла в соответствии с соглашениями операционной системы для текстовых файлов.Например, в Windows строка заканчивается на , и stdio преобразует ее в один , поскольку это соглашение C.При записи в текстовый файл один выводится как .
Это упрощает написание портативных программ на языке C, обрабатывающих текстовые файлы.Однако некоторые детали усложняются, и fseeking — одна из них.По этой причине стандарт C определяет fseek в текстовых файлах только в нескольких случаях:в самое начало, в самый конец, в текущую позицию и в предыдущую позицию, полученную с помощью ftell.Другими словами, вы не можете вычислить местоположение для поиска текстовых файлов.Или можете, но вам придется позаботиться обо всех деталях, связанных с платформой, самостоятельно.
Альтернативно вы можете использовать двоичные файлы и самостоятельно выполнять преобразования конца строк.Опять же, мобильность страдает.
В вашем случае, если вы просто хотите вернуться туда, где вы в последний раз выполняли fscancf, проще всего было бы использовать ftell непосредственно перед fscanf.
Другие советы
Это связано с тем, что fseek работает с байтами, тогда как fscanf разумно обрабатывает возврат каретки и перевод строки на два байта и воспринимает их как один символ.
Fseek не понимает содержимого файла и просто перемещает указатель файла на 10 символов назад.
fscanf в зависимости от ОС может по-разному интерпретировать символы новой строки;возможно даже, что fscanf вставит ^M, если вы работаете в DOS, а ^M не отображается в файле.Проверьте руководство, прилагаемое к компилятору C.
Только что попробовал это с VS2008 и обнаружил, что fscanf и fseek обрабатывают символы CR и LF одинаково (как один символ).
Итак, с двумя файлами:
0000000:3132 3334 3554 3738 3930 3132 3334 3536 12345X7890123456
и
0000000:3132 3334 350d 0a37 3839 3031 3233 3435 12345..789012345
Если я прочитаю 15 символов, я доберусь до вторых «5», затем вернутся к 10 символам, следующим прочитанным символом будет «X» в первом случае и CRLF во втором.
Это похоже на проблему, специфичную для ОС/компилятора.
Вы проверяли возвращаемое значение fscanf
?Опубликуйте код.
Взгляни на ungetc
.Возможно, вам придется выполнить цикл по нему.