Когда вы впервые открываете файл, вы можете использовать fseek()
до go до конца файла (но см. Примечание ниже), затем используйте ftell()
чтобы получить позицию и сохранить ее (как размер файла). Затем позвоните с rewind()
на go обратно в начало.
Затем возвращаемое значение из любого последующего вызова на ftell()
может быть вычтено из вашего сохраненного 'размера', чтобы получить смещение (расстояние) от текущей позиции до конца файла:
// Given a FILE* fp that's just been opened:
fseek(fp, 0, SEEK_END);
long int endpos = ftell(fp);
rewind(fp); // Or you can use fseek(fp, 0, SEEK_SET);
//...
// Later in your code:
long int dtoend = endpos - ftell(pf);
Но обратите внимание, что реализации не требуются для реализации SEEK_END
: со страницы cplusplus.com на fseek
ссылка выше:
- Реализациям библиотеки разрешено не оказывать значимой поддержки SEEK_END (поэтому код, использующий ее, не имеет реальной стандартной переносимости).
Просто чтобы уточнить (следует из некоторых комментариев): Код выше требует , чтобы значение endpos
было сохранено на время операций открытия / чтения файла. Один мог бы избежать этого, стремясь к концу и затем восстановив текущую позицию в любой точке, но это было бы гораздо менее эффективно. Например, можно написать функцию для получения расстояния до конца в любое время:
long int dtoend(FILE *fp)
{
long int curpos = ftell(fp); // Get current position
fseek(fp, 0, SEEK_END); // Go to the file's end
long endpos = ftell(fp); // Gets the file's size
fseek(fp, curpos, SEEK_SET); // Restore previous pos
return endpos - curpos; // Return the distance!
}
Примечание для использования с большими (> 2 ГБ) файлами: Приведенный выше код использует стандартные функции
fseek
и
ftell
, которые используют тип
long int
(который часто имеет ширину 32 бита) для позиций файла; Чтобы использовать подобный код для больших файлов, существует ряд (хотя и платформо-специфичных c) альтернатив ...
На Windows платформах с использованием MSVC
(или совместимых) компиляторов, там функции _ftelli64
и _fseeki64
, которые можно использовать практически так же, как и их «стандартные» аналоги; например, путем внесения следующих изменений в приведенный выше код:
//...
int64_t curpos = _ftelli64(fp); // Get current position
_fseeki64(fp, 0LL, SEEK_END); // Go to the file's end
//... and similar changes elsewhere
В системах Linux 64-разрядные вызовы реализуются как ftello
и fseeko
, если Вы убедитесь, что до #define _FILE_OFFSET_BITS 64
.
Другие платформы / компиляторы могут реализовывать (или оба) из вышеперечисленного или иметь некоторые другие, очень похожие 64- битовые замены.
Примечание # 2 - Обработка ошибок: Как указывается в комментариях, вызов
fseek
с
SEEK_END
в качестве аргумента
origin может завершиться ошибкой в ряде различных обстоятельств; например, если указатель файла равен
stdin
, если он относится к потоку канала, или (в некоторых системах), если файл открывается в
текстовом режиме † . Для обработки таких случаев нужно действительно проверить возвращаемое значение вызова
fseek
, которое будет
ненулевым , если оно не удалось. Итак, вот 64-битная версия функции
dtoend
с такой обработкой ошибок (обратите внимание, что для компиляторов, отличных от
MSVC
или
GNU
, вам нужно будет добавить соответствующие макросы определения для
bigseek
и
bigtell
функций):
#include <stdio.h>
#include <stdint.h>
#if defined (_MSC_VER) // MSVC/Windows...
#define bigtell _ftelli64
#define bigseek _fseeki64
#elif defined (__GNUC__) // GNU/Linux...
#define _FILE_OFFSET_BITS 64
#define bigtell ftello
#define bigseek fseeko
//
// Feel free to add other compiler/platform implementations
//
#else // Unknown platform/compiler - likely to cause warnings!
#define bigtell ftell
#define bigseek fseek
#endif
int64_t dtoend(FILE* fp)
{
int64_t curpos = bigtell(fp); // Saves the file's current position
if (bigseek(fp, 0LL, SEEK_END) != 0) return -1; // -1 can ONLY be an error condition
int64_t endpos = bigtell(fp); // Retrieve file size (end position)
bigseek(fp, curpos, SEEK_SET); // Restore previously saved position
return endpos - curpos; // Subtract to get distance from end
}
† С той же cplusplus.com страница, на которую ссылаются выше:
Для потоков, открытых в В текстовом режиме смещение должно быть либо нулем, либо значением, возвращаемым предыдущим вызовом ftell, а origin обязательно должно быть SEEK_SET. Если функция вызывается с другими значениями для этих аргументов, поддержка зависит от конкретной системы и реализации библиотеки (непереносимой).