Как определить размер файла на C?

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

#include <stdio.h>

unsigned int fsize(char* file){
  //what goes here?
}

Вам нужно будет использовать библиотечную функцию для получения сведений о файле. Поскольку C полностью независим от платформы, вам нужно будет сообщить нам, для какой платформы / операционной системы вы разрабатываете!

Chris Roberts 12.08.2008 01:18

Почему char* file, а почему не FILE* file? -1

user12211554 12.09.2019 22:16

@ user12211554 так что ... просто strlen!

asuka 16.02.2021 05:50

Обратите внимание: файл может увеличиваться между fsize и read. Будь осторожен.

asuka 16.02.2021 05:54
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
147
4
132 634
13
Перейти к ответу Данный вопрос помечен как решенный

Ответы 13

Если вас устраивает библиотека 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;
}

Это не стандартный C. Это часть стандарта POSIX, но не стандарта C.

Derek Park 12.08.2008 01:32

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

#define SEEKBOTTOM   2

fseek(handle, 0, SEEKBOTTOM)  

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

Я долгое время не программировал на C, но думаю, это должно сработать.

Вам не нужно определять что-то вроде SEEKBOTTOM. #include fseek (дескриптор, 0, SEEK_END);

sigjuice 26.03.2009 08:33

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

Поправил скобу и для тебя. ;)

Обновление: это не лучшее решение. В Windows он ограничен файлами размером 4 ГБ и, вероятно, медленнее, чем просто использование вызова для конкретной платформы, такого как GetFileSizeEx или stat64.

Да, ты должен. Однако, если нет действительно веской причины не писать для конкретной платформы, вам, вероятно, следует просто использовать вызов, специфичный для платформы, а не шаблон open / seek-end / tell / close.

Derek Park 18.04.2012 08:10

Извините за поздний ответ, но у меня серьезная проблема. Это приводит к зависанию приложения при доступе к файлам с ограниченным доступом (например, защищенным паролем или системным файлам). Есть ли способ при необходимости запросить у пользователя пароль?

Justin 29.03.2013 07:34

@Justin, вам, вероятно, следует открыть новый вопрос конкретно о проблеме, с которой вы столкнулись, и предоставить подробную информацию о платформе, на которой вы находитесь, о том, как вы получаете доступ к файлам и каково поведение.

Derek Park 02.04.2013 19:04

И C99, и C11 возвращают long int из ftell(). Литье (unsigned long) не улучшает диапазон, поскольку уже ограничен функцией. ftell() возвращает -1 при ошибке, и это запутывается с приведением типов. Предложите fsize() вернуть тот же тип, что и ftell().

chux - Reinstate Monica 13.01.2014 02:03

Я согласен. Актерский состав должен был соответствовать оригинальному прототипу в вопросе. Я не могу вспомнить, почему я превратил его в unsigned long вместо unsigned int.

Derek Park 28.01.2014 02:09

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

Quoting the C99 standard doc that i found online: "Setting the file position indicator to end-of-file, as with fseek(file, 0, SEEK_END), has undefined behavior for a binary stream (because of possible trailing null characters) or for any stream with state-dependent encoding that does not assuredly end in the initial shift state.**

Измените определение на 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
}

@mezhaka: Этот отчет CERT просто неверен. fseeko и ftello (или fseek и ftell, если вы застряли без первого и довольны ограничениями на размеры файлов, с которыми вы можете работать) - правильный способ определения длины файла. Решения на основе statне работает для многих «файлов» (таких как блочные устройства) и не переносятся в системы, отличные от POSIX.

R.. GitHub STOP HELPING ICE 24.10.2010 08:30

Это единственный способ получить размер файла во многих системах, несовместимых с posix (например, в моем очень минималистичном mbed)

Earlz 03.03.2012 03:36

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

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

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

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

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

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

Я использовал компиляторы, где off_t - 32 бита. Конечно, это во встроенных системах, где файлы размером 4 ГБ встречаются реже. В любом случае, POSIX также определяет off64_t и соответствующие методы, чтобы добавить путаницы.

Aaron Campbell 07.07.2016 23:12

Мне всегда нравятся ответы, которые предполагают наличие Windows и не делают ничего, кроме критики вопроса. Не могли бы вы добавить что-нибудь, совместимое с POSIX?

S.S. Anne 27.04.2019 21:52

@ JL2210 принятый ответ от Теда Персиваля показывает решение, совместимое с posix, поэтому я не вижу смысла повторять очевидное. Я (и еще 70 человек) подумал, что добавление примечания об окнах и отказ от использования 32-битных целых чисел со знаком для представления размеров файлов было добавлением ценности к этому. Ваше здоровье

Orion Edwards 28.04.2019 07:32

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

Ответ принят как подходящий

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

Это специфично для Linux / Unix - вероятно, стоит указать на это, поскольку в вопросе не указана ОС.

Drew Hall 03.08.2010 01:54

Вероятно, вы могли бы без проблем изменить тип возвращаемого значения на ssize_t и преобразовать размер из off_t. Казалось бы, имеет смысл использовать ssize_t :-) (не путать с size_t, которое не имеет знака и не может использоваться для обозначения ошибки.)

Ted Percival 06.08.2010 21:03

Для более переносимого кода используйте fseek + ftell, предложенный Дереком.

Ciro Santilli TRUMP BAN IS BAD 02.03.2015 10:57
Для более переносимого кода используйте fseek + ftell, предложенный Дереком. No. The C Стандартный specifically states that fseek() to SEEK_END on a binary file is undefined behavior. 7.19.9.2 Функция fseek... Двоичный поток не обязательно должен поддерживать вызовы fseek со значением источника SEEK_END, and as noted below, which is from footnote 234 on p. 267 of the linked C Standard, and which specifically labels fseek to SEEK_END in a binary stream as undefined behavior. .
Andrew Henle 06.04.2016 13:54

Из gnu libc руководство: ... [не-POSIX] системы проводят различие между файлами, содержащими текст, и файлами, содержащими двоичные данные, и средства ввода и вывода ISO C обеспечивают это различие. ... В библиотеке GNU C и во всех системах POSIX нет разницы между текстовыми потоками и двоичными потоками. Когда вы открываете поток, вы получаете тот же поток независимо от того, запрашиваете ли вы двоичный файл. Этот поток может обрабатывать любое содержимое файла и не имеет ограничений, которые иногда имеют текстовые потоки.

Small Boy 14.08.2020 11:02

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

//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);

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

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); 
    fclose(fp);
    return 
}

Не нужно ли закрывать файл?

Jerry Jeremiah 02.02.2017 03:53

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

user12211554 13.10.2019 04:05

ftell может не быть байтовым смещением для текстовых файлов (вы открываете файл в текстовом режиме)

M.M 17.02.2021 06:56

fp.close() не компилируется

M.M 17.02.2021 07:01

А что будет, если вы работаете в Windows и размер файла составляет 14 ГБ?

Andrew Henle 04.03.2021 18:31

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

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

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

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

Чем это отличается от Ответ Дерека 8-летней давности?

P.P 30.12.2016 00:51

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

Andrew Henle 30.12.2016 04:58

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);
}

If the file is stdin or a pipe. POSIX, ANSI C won't work.
It will going return 0 if the file is a pipe or stdin.

Opinion: You should use POSIX standard instead. Because, it has 64bit support.

struct _stat64 и __stat64() для _Windows.

Bob Stein 17.04.2019 16:23

Последний пример неверен, fopen принимает два аргумента

M.M 17.02.2021 06:58

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

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

Другие вопросы по теме