Использование fseek для возврата - PullRequest
5 голосов
/ 23 апреля 2009

Надежно ли использовать fseek для возврата символа fscanf операций?

Как, например, если у меня всего 10 символов fscanf, но я бы хотел вернуть 10 символов, могу ли я просто fseek(infile, -10, SEEK_CUR)?

В большинстве случаев это работает, но у меня, похоже, проблемы с персонажем ^M. Очевидно, fseek регистрирует его как символ, но fscanf не регистрирует его, поэтому в моем предыдущем примере блок из 10 символов, содержащий ^M, потребовал бы fseek(infile, -11, SEEK_CUR). fseek(infile, -10, SEEK_CUR) приведет к сокращению на 1 символ.

Почему это так?

Редактировать: я использовал fopen в текстовом режиме

Ответы [ 5 ]

8 голосов
/ 23 апреля 2009

Вы видите разницу между «текстовым» и «двоичным» файлом. Когда файл открывается в текстовом режиме (без 'b' во втором аргументе fopen), библиотека stdio может (действительно, должна) интерпретировать содержимое файла в соответствии с соглашениями операционной системы для текстовых файлов. Например, в Windows строка заканчивается на \ r \ n, и это переводится в одиночку \ n с помощью stdio, поскольку это соглашение на языке Си. При записи в текстовый файл один \ n выводится как \ r \ n.

Это облегчает написание переносимых программ на Си, которые обрабатывают текстовые файлы. Однако некоторые детали усложняются, и одним из них является fseeking. Из-за этого стандарт C определяет fseek в текстовых файлах только в нескольких случаях: в самом начале, в самом конце, в текущей позиции и в предыдущей позиции, которая была найдена с помощью ftell. Другими словами, вы не можете вычислить местоположение для поиска текстовых файлов. Или вы можете, но вы должны позаботиться обо всех деталях платформы самостоятельно.

Кроме того, вы можете использовать двоичные файлы и самостоятельно выполнять преобразования конца строки. Опять переносимость страдает.

В вашем случае, если вы просто хотите вернуться туда, где вы в последний раз выполняли fscancf, проще всего было бы использовать ftell непосредственно перед тем, как вы fscanf.

2 голосов
/ 23 апреля 2009

Это потому, что fseek работает с байтами, тогда как fscanf разумно обрабатывает, что возврат каретки и перевод строки являются двумя байтами, и проглатывает их как один символ.

1 голос
/ 23 апреля 2009

Только что попробовал это с 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 во втором.

Это похоже на специфическую проблему ОС / компилятора.

1 голос
/ 23 апреля 2009

Fseek не понимает содержимого файла и просто перемещает указатель файла на 10 символов назад.

fscanf, в зависимости от ОС, может интерпретировать переводы строк по-разному; может даже случиться так, что fscanf вставит ^ M, если вы находитесь в DOS, и ^ M не появляется в файле. Проверьте ваше руководство, поставляемое с вашим компилятором C

0 голосов
/ 23 апреля 2009

Вы проверяли возвращаемое значение fscanf? Разместите некоторый код.

Взгляните на ungetc. Возможно, вам придется запустить цикл по нему.

...