Как вы определяете размер файла в C?

Как я могу определить размер файла в байтах?

#include <stdio.h>

unsigned int fsize(char* file){
  //what goes here?
}
11.08.2008 21:16:30
Вам нужно будет использовать библиотечную функцию для получения подробной информации о файле. Поскольку C полностью независим от платформы, вам нужно сообщить нам, для какой платформы / операционной системы вы разрабатываете!
Chris Roberts 11.08.2008 21:18:31
Почему char* file, почему нет FILE* file? -1
Asadefa 12.09.2019 19:16:58
-1, потому что файловые функции должны принимать файловые дескрипторы, а не пути к файлам
Asadefa 19.01.2020 20:37:31
14 ОТВЕТОВ
РЕШЕНИЕ

На основе кода 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» .

144
4.08.2018 02:03:49
Это специфично для Linux / Unix - вероятно, стоит указать на это, поскольку в вопросе не указана ОС.
Drew Hall 2.08.2010 21:54:30
Вы могли бы, вероятно, изменить тип возвращаемого значения на ssize_t и привести размер к значению off_t без каких-либо проблем. Казалось бы, имеет больше смысла использовать ssize_t :-) (не путать с size_t, который не подписан и не может использоваться для обозначения ошибки.)
Ted Percival 6.08.2010 17:03:00
Для более переносимого кода используйте fseek+, ftellкак предложено Дереком.
Ciro Santilli 冠状病毒审查六四事件法轮功 2.03.2015 07:57:21
Для более переносимого кода используйте fseek+, ftellкак предложено Дереком. Нет. Стандарт C конкретно указывает, что fseek()для SEEK_ENDдвоичного файла поведение не определено. 7.19.9.2 fseekФункция ... Бинарный поток не обязательно должен поддерживать fseekвызовы со значением откудаSEEK_END и, как отмечено ниже, которое взято из сноски 234 на с. 267 связанных C стандарта, и которые специфически этикетками , fseekчтобы SEEK_ENDв двоичном потоке в качестве неопределенного поведения. ,
Andrew Henle 6.04.2016 10:54:28

Если вы хорошо используете библиотеку 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;
}
5
1.10.2016 12:26:46
Это не стандарт C. Это часть стандарта POSIX, но не стандарт C.
Derek Park 11.08.2008 21:32:20

Вы можете открыть файл, перейти к 0 смещению относительно нижней части файла с помощью

#define SEEKBOTTOM   2

fseek(handle, 0, SEEKBOTTOM)  

значение, возвращаемое из fseek - это размер файла.

Я давно не писал код на С, но думаю, что это должно сработать.

-3
11.08.2008 21:23:59
Вы не должны определять что-то вроде SEEKBOTTOM. #include <stdio.h> fseek (handle, 0, SEEK_END);
sigjuice 26.03.2009 05:33:06

Решение Мэтта должно работать, за исключением того, что это 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.

30
18.04.2012 04:19:28
Да, ты должен. Однако, если нет действительно веской причины не писать для конкретной платформы, вам, вероятно, следует просто использовать вызов для конкретной платформы, а не шаблон open / seek-end / tell / close.
Derek Park 18.04.2012 04:10:38
Извините за поздний ответ, но у меня есть серьезная проблема здесь. Это приводит к зависанию приложения при доступе к закрытым файлам (например, защищенным паролем или системным файлам). Можно ли попросить пользователя ввести пароль при необходимости?
Justin 29.03.2013 03:34:11
@ Джастин, вам, вероятно, следует открыть новый вопрос, конкретно о проблеме, с которой вы столкнулись, и предоставить подробную информацию о платформе, на которой вы работаете, как вы получаете доступ к файлам и каково поведение.
Derek Park 2.04.2013 15:04:13
И С99, и С11 возвращаются long intиз ftell(). (unsigned long)литье не улучшает диапазон, так как уже ограничен функцией. ftell()верните -1 в случае ошибки, и это будет запутано с актерами. Предлагаем fsize()вернуть тот же тип, что и ftell().
chux - Reinstate Monica 12.01.2014 22:03:43
Я согласен. Актерский состав должен был соответствовать оригинальному прототипу в вопросе. Я не могу вспомнить, почему я превратил его в unsigned long вместо unsigned int, хотя.
Derek Park 27.01.2014 22:09:15

** Не делай этого ( почему? ):

Цитируя стандартный документ 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
}
15
6.08.2019 16:14:00
@mezhaka: Этот отчет CERT просто неверен. fseekoи ftello(или fseekи ftellесли вы застряли без первого и счастливым с ограничениями на размеры файлов вы можете работать с) , являются правильным способом , чтобы определить длину файла. statРешения на основе не работают на многих «файлах» (таких как блочные устройства) и не переносимы на системы, не поддерживающие POSIX.
R.. GitHub STOP HELPING ICE 24.10.2010 04:30:12
Это единственный способ получить размер файла во многих системах, не поддерживающих posix (например, в моем очень минималистичном mbed)
Earlz 2.03.2012 23:36:03

Быстрый поиск в Google нашел метод, использующий fseek и ftell, и ветку с этим вопросом с ответами, что это нельзя сделать просто на C другим способом.

Вы можете использовать библиотеку переносимости, такую ​​как NSPR (библиотека, поддерживающая Firefox), или проверить ее реализацию (скорее волосатую).

3
5.10.2011 18:42:00

Не используйте int. В наши дни файлы размером более 2 гигабайт часто встречаются как грязь

Не используйте unsigned int. Файлы размером более 4 гигабайт часто встречаются как немного менее распространенная грязь

Стандартная библиотека IIRC определяет off_tкак 64-разрядное целое число без знака, которое каждый должен использовать. Мы можем переопределить его как 128-битный через несколько лет, когда у нас появятся 16 эксабайтных файлов.

Если вы работаете в Windows, вам следует использовать GetFileSizeEx - он на самом деле использует 64-разрядное целое число со знаком, поэтому они начнут сталкиваться с проблемами с 8 эксабайтными файлами. Глупый Microsoft! :-)

74
11.08.2008 22:14:19
Я использовал компиляторы, где off_t составляет 32 бита. Конечно, это на встроенных системах, где файлы размером 4 ГБ встречаются реже. В любом случае, POSIX также определяет off64_t и соответствующие методы, чтобы добавить к путанице.
Aaron Campbell 7.07.2016 20:12:20
Я всегда люблю ответы, которые предполагают Windows и ничего не делают, кроме как критиковать вопрос. Не могли бы вы добавить что-нибудь совместимое с POSIX?
S.S. Anne 27.04.2019 18:52:22
@ JL2210 Принятый ответ от Теда Персиваля показывает решение, совместимое с posix, поэтому я не вижу смысла повторять очевидное. Я (и 70 других) подумали, что добавление примечания об окнах и не использовать 32-битные целые числа со знаком для представления размеров файлов является дополнительным преимуществом. Приветствия
Orion Edwards 28.04.2019 04:32:10

А если вы создаете приложение для Windows, используйте API GetFileSizeEx, так как ввод / вывод файла CRT является грязным, особенно для определения длины файла, из-за особенностей представления файлов в разных системах;)

5
12.08.2008 00:15:35

Я использовал этот набор кода, чтобы найти длину файла.

//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);
1
8.02.2014 01:54:26

Глядя на вопрос, ftellможно легко получить количество байтов.

  long size = ftell(FILENAME);
  printf("total size is %ld bytes",size);
-4
20.01.2020 00:56:59
ftellожидает дескриптор файла, а не имя файла, в качестве аргумента.
Barmar 30.09.2016 14:57:14
@ Barmar, Нет ftellне ожидает файловый дескриптор, он ожидает FILE*вместо этого. Сначала посмотрите страницу руководства!
user9258013 13.01.2019 03:14:08
Подход совершенно неправильный, постоянный, который ftellбы возвращался 0каждый раз!
user9258013 13.01.2019 03:15:24
Этот ответ совершенно неправильный, так как для fseek()начала вам нужно использовать сначала поиск конца файла, а также ftell()ожидает a FILE *, а не строку! Вы бы хорошо обнародовали свой ответ.
Asadefa 13.10.2019 01:04:20

Вот простая и чистая функция, которая возвращает размер файла.

long get_file_size(char *path)
{
    FILE *fp;
    long size = -1;
    /* Open file for reading */
    fp = fopen(path, "r");
    fseek(fp, 0, SEEK_END);
    size = ftell(fp); 
    fp.close();
    return 
}
0
9.05.2019 14:17:52
Вам не нужно закрывать файл?
Jerry Jeremiah 2.02.2017 00:53:57
Нет, мне не нравятся функции, которые ожидают пути. Вместо этого, пожалуйста, сделайте так, чтобы я ожидал указатель файла
Asadefa 13.10.2019 01:05:52

Попробуй это --

fseek(fp, 0, SEEK_END);
unsigned long int file_size = ftell(fp);
rewind(fp);

Что это делает в первую очередь, ищите до конца файла; затем сообщите, где находится указатель файла. И наконец (это необязательно), он перематывает назад к началу файла. Обратите внимание, что это fpдолжен быть двоичный поток.

file_size содержит количество байтов в файле. Обратите внимание, что, поскольку (согласно climits.h) тип unsigned long ограничен 4294967295 байтами (4 гигабайта), вам нужно будет найти другой тип переменной, если вы, вероятно, имеете дело с файлами большего размера.

1
19.02.2017 19:47:09
Чем это отличается от ответа Дерека от 8 лет назад?
P.P 29.12.2016 21:51:09
Это неопределенное поведение для двоичного потока, а для текстового потока ftellне возвращает значение, представляющее число байтов, которые можно прочитать из файла.
Andrew Henle 30.12.2016 01:58:05

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 бит.

9
9.01.2019 17:24:17
struct _stat64и __stat64()для _Windows.
Bob Stein 17.04.2019 13:23:07

У меня есть функция, которая хорошо работает только с stdio.h. Мне это очень нравится, оно работает очень хорошо и довольно лаконично:

size_t fsize(FILE *File) {
    size_t FSZ;
    fseek(File, 0, 2);
    FSZ = ftell(File);
    rewind(File);
    return FSZ;
}
0
11.07.2019 22:22:44