Как вы определяете размер файла в C?
Как я могу определить размер файла в байтах?
#include <stdio.h>
unsigned int fsize(char* file){
//what goes here?
}
17 ответов
На основе кода NilObject:
#include <sys/stat.h>
#include <sys/types.h>
off_t fsize(const char *filename) {
struct stat st;
if (stat(filename, &st) == 0)
return st.st_size;
return -1;
}
Изменения:
- Сделал аргумент имени файла
const char
, - Исправил
struct stat
определение, в котором отсутствовало имя переменной. - Возвращает
-1
по ошибке вместо0
, что было бы неоднозначно для пустого файла.off_t
это тип со знаком, так что это возможно.
Если ты хочешь fsize()
чтобы напечатать сообщение об ошибке, вы можете использовать это:
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
off_t fsize(const char *filename) {
struct stat st;
if (stat(filename, &st) == 0)
return st.st_size;
fprintf(stderr, "Cannot determine size of %s: %s\n",
filename, strerror(errno));
return -1;
}
На 32-битных системах вы должны скомпилировать это с опцией -D_FILE_OFFSET_BITS=64
, иначе off_t
будет содержать только значения до 2 ГБ. Подробности смотрите в разделе "Использование LFS" в разделе " Поддержка больших файлов в Linux".
Не использовать int
, В наши дни файлы размером более 2 гигабайт часто встречаются как грязь
Не использовать unsigned int
, Файлы размером более 4 гигабайт часто встречаются как немного менее распространенная грязь
IIRC стандартная библиотека определяет off_t
как 64-разрядное целое число без знака, которое каждый должен использовать. Мы можем переопределить его как 128-битный через несколько лет, когда у нас появятся 16 эксабайтных файлов.
Если у вас Windows, вы должны использовать GetFileSizeEx - он на самом деле использует 64-разрядное целое число со знаком, поэтому они начнут сталкиваться с проблемами с 8 эксабайтными файлами. Глупый Microsoft!:-)
Решение Мэтта должно работать, за исключением того, что это C++ вместо C, и первоначальное сообщение не должно быть необходимым.
unsigned long fsize(char* file)
{
FILE * f = fopen(file, "r");
fseek(f, 0, SEEK_END);
unsigned long len = (unsigned long)ftell(f);
fclose(f);
return len;
}
Исправил вашу скобку для вас тоже.;)
Обновление: это не самое лучшее решение. Он ограничен 4 ГБ файлами в Windows и, вероятно, медленнее, чем просто использование вызова конкретной платформы, такого как GetFileSizeEx
или же stat64
,
** Не делай этого ( почему?):
Цитируя стандартный документ C99, который я нашел в Интернете: "Установка индикатора положения файла в конец файла, как и в случае с fseek(file, 0, SEEK_END), имеет неопределенное поведение для двоичного потока (из-за возможных завершающих нулевых символов) или для любого потока с кодированием, зависящим от состояния, которое не обязательно заканчивается в начальном состоянии сдвига.**
Измените определение на int, чтобы можно было передавать сообщения об ошибках, а затем используйте fseek() и ftell(), чтобы определить размер файла.
int fsize(char* file) {
int size;
FILE* fh;
fh = fopen(file, "rb"); //binary mode
if(fh != NULL){
if( fseek(fh, 0, SEEK_END) ){
fclose(fh);
return -1;
}
size = ftell(fh);
fclose(fh);
return size;
}
return -1; //error
}
POSIX
Стандарт POSIX имеет свой собственный метод для получения размера файла.
Включить sys/stat.h
заголовок для использования функции.
конспект
- Получить статистику файла, используя
stat(3)
, - Получить
st_size
имущество.
Примеры
Примечание: он ограничивает размер 4GB
, Если не Fat32
файловую систему, тогда используйте 64-битную версию!
#include <stdio.h>
#include <sys/stat.h>
int main(int argc, char** argv)
{
struct stat info;
stat(argv[1], &info);
// 'st' is an acronym of 'stat'
printf("%s: size=%ld\n", argv[1], info.st_size);
}
#include <stdio.h>
#include <sys/stat.h>
int main(int argc, char** argv)
{
struct stat64 info;
stat64(argv[1], &info);
// 'st' is an acronym of 'stat'
printf("%s: size=%ld\n", argv[1], info.st_size);
}
ANSI C (стандарт)
ANSI C не предоставляет прямой способ определения длины файла.
Нам придется использовать наш разум. Сейчас мы будем использовать подход поиска!
конспект
- Ищите файл до конца, используя
fseek(3)
, - Получить текущую позицию, используя
ftell(3)
,
пример
#include <stdio.h>
int main(int argc, char** argv)
{
FILE* fp = fopen(argv[1]);
int f_size;
fseek(fp, 0, SEEK_END);
f_size = ftell(fp);
rewind(fp); // to back to start again
printf("%s: size=%ld", (unsigned long)f_size);
}
Если файл
stdin
или труба. POSIX, ANSI C не будет работать.
Будет возвращаться0
если файл представляет собой трубу илиstdin
,Мнение: Вы должны вместо этого использовать стандарт POSIX. Потому что он имеет поддержку 64 бит.
Если вы хорошо используете библиотеку std c:
#include <sys/stat.h>
off_t fsize(char *file) {
struct stat filestat;
if (stat(file, &filestat) == 0) {
return filestat.st_size;
}
return 0;
}
А если вы создаете приложение для Windows, используйте API GetFileSizeEx, так как ввод / вывод файла CRT запутан, особенно для определения длины файла, из-за особенностей представления файлов в разных системах;)
Быстрый поиск в Google нашел метод, использующий fseek и ftell, и ветку с этим вопросом с ответами, что это нельзя сделать просто на C другим способом.
Вы можете использовать библиотеку переносимости, такую как NSPR (библиотека, поддерживающая Firefox), или проверить ее реализацию (скорее волосатую).
Я использовал этот набор кода, чтобы найти длину файла.
//opens a file with a file descriptor
FILE * i_file;
i_file = fopen(source, "r");
//gets a long from the file descriptor for fstat
long f_d = fileno(i_file);
struct stat buffer;
fstat(f_d, &buffer);
//stores file size
long file_length = buffer.st_size;
fclose(i_file);
В простом ISO C есть только один способ определить размер файла, который гарантированно сработает: прочитать весь файл с самого начала, пока не встретите конец файла.
Однако это крайне неэффективно. Если вы хотите более эффективное решение, вам придется либо
- полагаться на поведение, зависящее от платформы, или
- вернуться к функциям, специфичным для платформы, таким как
stat
в линуксе илиGetFileSize
на Microsoft Windows.
В отличие от того, что предлагали другие ответы, следующий код не гарантирует работу:
fseek( fp, 0, SEEK_END );
long size = ftell( fp );
Даже если мы предположим, что тип данных достаточно велик, чтобы представить размер файла (что сомнительно на некоторых платформах, особенно в Microsoft Windows), опубликованный код имеет следующие проблемы:
Не гарантируется, что опубликованный код будет работать с текстовыми потоками, поскольку согласно §7.21.9.4 ¶2 стандарта ISO C11 значение индикатора позиции файла, возвращаемоеftell
содержит неустановленную информацию. Только для двоичных потоков это значение гарантированно равно количеству символов с начала файла. Для текстовых потоков такой гарантии нет.
Также не гарантируется, что опубликованный код будет работать с бинарными потоками, поскольку согласно §7.21.9.2 ¶3 стандарта ISO C11 бинарные потоки не требуются для полноценной поддержкиSEEK_END
.
При этом на большинстве распространенных платформ размещенный код будет работать, если мы предположим, что тип данныхlong
достаточно велик, чтобы представить размер файла.
Однако в Microsoft Windows символы (возврат каретки с последующим переводом строки) будут преобразованы для текстовых потоков (но не для двоичных потоков), так что размер полученного файла будет учитываться.\r\n
как два байта, хотя вы читаете только один символ (\n
) в текстовом режиме. Поэтому результаты, которые вы получите, не будут последовательными.
На платформах, основанных на POSIX (например, Linux), это не проблема, поскольку на этих платформах нет разницы между текстовым и двоичным режимами.
Попробуй это --
fseek(fp, 0, SEEK_END);
unsigned long int file_size = ftell(fp);
rewind(fp);
Сначала это делается, ищите до конца файла; затем сообщите, где находится указатель файла. И наконец (это необязательно), он перематывает назад к началу файла. Обратите внимание, что fp
должен быть двоичным потоком.
file_size содержит количество байтов, которое содержит файл. Обратите внимание, что, поскольку (согласно climits.h) тип unsigned long ограничен 4294967295 байтами (4 гигабайта), вам нужно будет найти другой тип переменной, если вы, вероятно, имеете дело с файлами большего размера.
С++ MFC , извлеченный из сведений о файле Windows, не уверен, что это лучше, чем поиск, но если он извлечен из метаданных, я думаю, что это быстрее, потому что ему не нужно читать весь файл
ULONGLONG GetFileSizeAtt(const wchar_t *wFile)
{
WIN32_FILE_ATTRIBUTE_DATA fileInfo;
ULONGLONG FileSize = 0ULL;
//https://docs.microsoft.com/nl-nl/windows/win32/api/fileapi/nf-fileapi-getfileattributesexa?redirectedfrom=MSDN
//https://docs.microsoft.com/nl-nl/windows/win32/api/fileapi/ns-fileapi-win32_file_attribute_data?redirectedfrom=MSDN
if (GetFileAttributesEx(wFile, GetFileExInfoStandard, &fileInfo))
{
ULARGE_INTEGER ul;
ul.HighPart = fileInfo.nFileSizeHigh;
ul.LowPart = fileInfo.nFileSizeLow;
FileSize = ul.QuadPart;
}
return FileSize;
}
Вот простая и чистая функция, которая возвращает размер файла.
long get_file_size(char *path)
{
FILE *fp;
/* Open file for reading */
fp = fopen(path, "r");
fseek(fp, 0, SEEK_END);
return ftell(fp);
}
Вам нужно будет использовать библиотечную функцию для получения подробной информации о файле. Поскольку C полностью независим от платформы, вам нужно сообщить нам, для какой платформы / операционной системы вы разрабатываете!
У меня есть функция, которая хорошо работает только с stdio.h
, Мне это очень нравится, оно работает очень хорошо и довольно лаконично:
size_t fsize(FILE *File) {
size_t FSZ;
fseek(File, 0, 2);
FSZ = ftell(File);
rewind(File);
return FSZ;
}
Глядя на вопрос, ftell
может легко получить количество байтов.
long size ;
size = ftell(FILENAME);
printf("total size is %ld bytes",size);
Вы можете открыть файл, перейти к 0 смещению относительно нижней части файла с помощью
#define SEEKBOTTOM 2
fseek(handle, 0, SEEKBOTTOM)
значение, возвращаемое из fseek - это размер файла.
Я давно не писал код на C, но думаю, что это должно сработать.