Есть ли случаи, когда fseek / ftell может указывать неправильный размер файла? - PullRequest
4 голосов
/ 04 февраля 2012

В C или C ++ для получения размера файла можно использовать следующее:

const unsigned long long at_beg = (unsigned long long) ftell(filePtr);
fseek(filePtr, 0, SEEK_END);
const unsigned long long at_end = (unsigned long long) ftell(filePtr);
const unsigned long long length_in_bytes = at_end - at_beg;
fprintf(stdout, "file size: %llu\n", length_in_bytes);

Существуют ли среды разработки, компиляторы или операционные системы, которые могут возвращать неправильный размер файла из этого кода на основеpadding или другая информация, специфичная для конкретной ситуации?Были ли изменения в спецификации C или C ++ в 1999 году, что привело бы к тому, что этот код больше не работал в некоторых случаях?

Для этого вопроса, пожалуйста, предположим, что я добавляю поддержку больших файлов, компилируя с флагами1006 *.Спасибо.

Ответы [ 4 ]

6 голосов
/ 04 февраля 2012

Он не будет работать с неприемлемыми файлами, такими как /proc/cpuinfo или /dev/stdin или /dev/tty, или с файлами каналов, полученными с popen

И он не будет работать, если этот файл будет записан другим процессом одновременно.

Использование функции Posix stat , вероятно, более эффективно и надежно. Конечно, эта функция может быть недоступна в системах, отличных от Posix.

3 голосов
/ 04 февраля 2012

Функции fseek и ftell определены стандартом языка ISO C.

Ниже приводится последний открытый проект стандарта C 2011 года, но стандарты ISO C 1990, 1999 и 2011 годов очень похожи в этой области, если не идентичны.

7.21.9.4:

Функция ftell получает текущее значение позиции файла индикатор потока, на который указывает stream . Для двоичного потока значение - это количество символов в начале файла. Для текстового потока его индикатор положения файла содержит неопределенный информация, используемая функцией fseek для возврата файла индикатор положения потока в его положение во время ftell вызов; разница между двумя такими возвращаемыми значениями не обязательно значимая мера количества написанных символов или читать.

7.21.9.2:

Функция fseek устанавливает индикатор положения файла для потока на который указывает stream . Если происходит ошибка чтения или записи, ошибка Индикатор для потока установлен и fseek не работает.

Для двоичного потока - новая позиция, измеренная в символах из начало файла, получается путем добавления offset к позиция указана откуда . Указанная позиция является начало файла, если откуда равно SEEK_SET , текущее значение индикатора положения файла, если SEEK_CUR , или конец файла, если SEEK_END . Бинарный поток не обязательно должен поддерживать fseek вызовов со значением откуда SEEK_END .

Для текстового потока либо смещение должно быть равно нулю, либо смещение должно быть значением, возвращенным ранее успешным вызовом ftell функция для потока, связанного с тем же файлом, и , откуда должно быть SEEK_SET .

Нарушение любого из условий "must" делает поведение вашей программы неопределенным.

Так, если файл был открыт в двоичном режиме, ftell дает вам количество символов от начала файла - но fseek относительно конца файла (SEEK_END) не обязательно осмысленный. Это подходит для систем, которые хранят двоичные файлы в целых блоках и не отслеживают, сколько было записано в последний блок.

Если файл был открыт в текстовом режиме, вы можете искать начало или конец файла со смещением 0, или вы можете искать позицию, заданную ранним вызовом ftell; fseek с любыми другими аргументами имеет неопределенное поведение. Это подходит для систем, в которых количество символов, считываемых из текстового файла, не обязательно соответствует количеству байтов в файле. Например, в Windows при чтении пары CR-LF ("\r\n") читается только один символ, но в файле увеличивается на 2 байта.

На практике в Unix-подобных системах текстовый и двоичный режимы ведут себя одинаково, и метод fseek / ftell будет работать. Я подозреваю, это будет работать в Windows (я предполагаю, что ftell даст смещение в байтах, которое может не совпадать с количеством раз, которое вы могли бы вызвать getchar() в текстовом режиме).

Обратите внимание, что ftell() возвращает результат типа long. В системах, где long составляет 32 бита, этот метод не может работать с файлами размером 2 ГБ или более.

Возможно, вам лучше использовать какой-нибудь системный метод, чтобы получить размер файла. Поскольку метод fseek / ftell в любом случае зависит от системы, например, stat() в Unix-подобных системах.

С другой стороны, fseek и ftell могут работать, как вы ожидаете, на большинстве систем, с которыми вы, вероятно, столкнетесь. Я уверен, что есть системы, где это не будет работать; извините, но у меня нет подробностей.

Если работа в Linux и Windows достаточно хороша, и вас не интересуют большие файлы, тогда метод fseek / ftell, вероятно, подходит.В противном случае вам следует рассмотреть возможность использования системного метода для определения размера файла.

И помните, что все, что говорит вам о размере файла, может сообщить вам только его размер в этот момент.Размер файла может измениться, прежде чем вы получите к нему доступ.

2 голосов
/ 04 февраля 2012

1) Внешне ваш код выглядит «ОК» - я не вижу никаких проблем с ним.

2) Нет - не существует «спецификации C или C ++», которая бы влияла на fseek.Там есть спецификация Posix:

3) Если вы хотите "размер файла", мой первый выбор, вероятно, будет "стат ()».Вот спецификация Posix:

4) Если с вашим методом что-то не так, то мое первое предположение - «поддержка больших файлов».

Например, многие ОС имели параллельные API-интерфейсы "fseek ()" и "fseek64 ()".

'Надеюсь, это поможет .. PSM

1 голос
/ 04 февраля 2012

POSIX определяет возвращаемое значение из fseek как «измеренное в байтах от начала файла». Ваш at_beg всегда будет нулевым (при условии, что это новый открытый файл).

Итак, предполагая, что:

  1. файл доступен для поиска
  2. нет никаких проблем с параллелизмом, о которых стоит беспокоиться
  3. размер файла представлен в типе данных, используемом выбранным вами вариантом fseek / ftell

тогда ваш код должен работать в любой POSIX-совместимой системе.

...