Как я могу получить размер файла в C? [Дубликат]

327

Возможный дубликат:
Как вы определяете размер файла в C?

Как я могу узнать размер файла, который я открыл приложением, написанным на C? Я хотел бы знать размер, потому что я хочу поместить содержимое загруженного файла в строку, которую я выделяю с помощью malloc(). Просто пишу malloc(10000*sizeof(char)); ИМХО это плохая идея.

  • 38
    Обратите внимание, что sizeof (char) равен 1 по определению.
  • 9
    Да, но компилятор некоторой эзотерической платформы может определять char как 2 байта - тогда программа выделяет больше, чем необходимо. Никогда нельзя быть слишком уверенным.
Показать ещё 7 комментариев
Теги:
file
size

8 ответов

412
Лучший ответ

Вам нужно найти конец файла, а затем запросить позицию:

fseek(fp, 0L, SEEK_END);
sz = ftell(fp);

Затем вы можете запросить назад, например:

fseek(fp, 0L, SEEK_SET);

или (если хотите перейти к началу)

rewind(fp);
  • 11
    @camh - Спасибо, парень. Этот комментарий решил проблему с алгоритмом определения размера файла. Для записи можно открыть файл в двоичном режиме, поставив 'b' в конце строки режима fopen.
  • 4
    LOL, да, Windows унаследовала эту глупую чепуху в текстовом / бинарном режиме от DOS. Это легко забыто в наши дни. На самом деле стандарт POSIX даже предписывает, что любая система POSIX должна быть в состоянии справиться с флагом "b" в вызовах fopen (чтобы быть совместимым со стандартом C!), Но, с другой стороны, он требует, чтобы реализация полностью его игнорировала , поскольку этот флаг не влияет на системы POSIX (те, которые не знают ничего о текстовом режиме, всегда открываются в двоичном режиме).
Показать ещё 12 комментариев
337

Использование стандартной библиотеки:

Предполагая, что ваша реализация объективно поддерживает SEEK_END: ​​

fseek(f, 0, SEEK_END); // seek to end of file
size = ftell(f); // get current file pointer
fseek(f, 0, SEEK_SET); // seek back to beginning of file
// proceed with allocating memory and reading the file

Linux/POSIX:

Вы можете использовать stat (если вы знаете имя файла) или fstat (если у вас есть файловый дескриптор).

Вот пример stat:

#include <sys/stat.h>
struct stat st;
stat(filename, &st);
size = st.st_size;

Win32:

Вы можете использовать GetFileSize или GetFileSizeEx.

  • 0
    нужна проверка ошибок
  • 14
    Пожалуйста, обратите внимание, что я пропустил проверку ошибок в интересах ясности.
Показать ещё 11 комментариев
99

Если у вас есть файловый дескриптор, fstat() возвращает структуру stat, которая содержит размер файла.

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

// fd = fileno(f); //if you have a stream (e.g. from fopen), not a file descriptor.
struct stat buf;
fstat(fd, &buf);
off_t size = buf.st_size;
  • 3
    Добавьте "fd = fileno (f);" если у вас есть поток (например, из fopen), а не дескриптор файла. Требуется проверка ошибок.
  • 12
    Конечно, требуется проверка ошибок - это только усложнит пример.
Показать ещё 4 комментария
14

Я закончил тем, что просто сделал короткую и приятную функцию fsize (заметьте, не проверяйте ошибок)

int fsize(FILE *fp){
    int prev=ftell(fp);
    fseek(fp, 0L, SEEK_END);
    int sz=ftell(fp);
    fseek(fp,prev,SEEK_SET); //go back to where we were
    return sz;
}

Это глупо, что стандартная библиотека C не имеет такой функции, но я могу понять, почему это было бы сложно, поскольку не каждый "файл" имеет размер (например, /dev/null)

  • 0
    Хорошая точка для восстановления индикатора предыдущей позиции файлового потока.
9

Вы считали, что не вычисляете размер файла и при необходимости увеличиваете массив? Здесь пример (с ошибкой проверки пропущен):

#define CHUNK 1024

/* Read the contents of a file into a buffer.  Return the size of the file 
 * and set buf to point to a buffer allocated with malloc that contains  
 * the file contents.
 */
int read_file(FILE *fp, char **buf) 
{
  int n, np;
  char *b, *b2;

  n = CHUNK;
  np = n;
  b = malloc(sizeof(char)*n);
  while ((r = fread(b, sizeof(char), CHUNK, fp)) > 0) {
    n += r;
    if (np - n < CHUNK) { 
      np *= 2;                      // buffer is too small, the next read could overflow!
      b2 = malloc(np*sizeof(char));
      memcpy(b2, b, n * sizeof(char));
      free(b);
      b = b2;
    }
  }
  *buf = b;
  return n;
}

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

  • 19
    Возможно, здесь можно использовать функцию realloc вместо промежуточного указателя и необходимости free() .
  • 0
    Это имеет реальный недостаток: O (n ^ 2) ... размер вещи, которую вы должны скопировать, увеличивается. ОК для маленьких файлов, УЖАСНЫЙ для больших. Если у вас есть блок размером 1 КБ и файл размером 100 МБ, вы в конечном итоге копируете (если я правильно сделал математику) примерно 1E17 байт. Это может быть патологическим примером, но он демонстрирует, почему вы не должны этого делать.
Показать ещё 3 комментария
8

Если вы работаете в Linux, серьезно подумайте о том, чтобы использовать функцию g_file_get_contents из glib. Он обрабатывает весь код для загрузки файла, выделения памяти и ошибок обработки.

  • 34
    Если вы работаете в Linux и хотите иметь зависимость от glib, то это так.
  • 2
    Неплохая проблема, поскольку glib сейчас используется и приложениями GTK, и KDE. Он также доступен в Mac OS X и Windows, но там он не настолько стандартен.
Показать ещё 4 комментария
3

Как использовать lseek/fseek/stat/fstat, чтобы получить размер файла?

#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>


void
fseek_filesize(const char *filename)
{
    FILE *fp = NULL;
    long off;

    fp = fopen(filename, "r");
    if (fp == NULL)
    {
        printf("failed to fopen %s\n", filename);
        exit(EXIT_FAILURE);
    }

    if (fseek(fp, 0, SEEK_END) == -1)
    {
        printf("failed to fseek %s\n", filename);
        exit(EXIT_FAILURE);
    }

    off = ftell(fp);
    if (off == (long)-1)
    {
        printf("failed to ftell %s\n", filename);
        exit(EXIT_FAILURE);
    }

    printf("[*] fseek_filesize - file: %s, size: %ld\n", filename, off);

    if (fclose(fp) != 0)
    {
        printf("failed to fclose %s\n", filename);
        exit(EXIT_FAILURE);
    }
}

void
fstat_filesize(const char *filename)
{
    int fd;
    struct stat statbuf;

    fd = open(filename, O_RDONLY, S_IRUSR | S_IRGRP);
    if (fd == -1)
    {
        printf("failed to open %s\n", filename);
        exit(EXIT_FAILURE);
    }

    if (fstat(fd, &statbuf) == -1)
    {
        printf("failed to fstat %s\n", filename);
        exit(EXIT_FAILURE);
    }

    printf("[*] fstat_filesize - file: %s, size: %lld\n", filename, statbuf.st_size);

    if (close(fd) == -1)
    {
        printf("failed to fclose %s\n", filename);
        exit(EXIT_FAILURE);
    }
}

void
stat_filesize(const char *filename)
{
    struct stat statbuf;

    if (stat(filename, &statbuf) == -1)
    {
        printf("failed to stat %s\n", filename);
        exit(EXIT_FAILURE);
    }

    printf("[*] stat_filesize - file: %s, size: %lld\n", filename, statbuf.st_size);

}

void
seek_filesize(const char *filename)
{
    int fd;
    off_t off;

    if (filename == NULL)
    {
        printf("invalid filename\n");
        exit(EXIT_FAILURE);
    }

    fd = open(filename, O_RDONLY, S_IRUSR | S_IRGRP);
    if (fd == -1)
    {
        printf("failed to open %s\n", filename);
        exit(EXIT_FAILURE);
    }

    off = lseek(fd, 0, SEEK_END);
    if (off == (off_t)-1)
    {
        printf("failed to lseek %s\n", filename);
        exit(EXIT_FAILURE);
    }

    printf("[*] seek_filesize - file: %s, size: %lld\n", filename, off);

    if (close(fd) == -1)
    {
        printf("failed to close %s\n", filename);
        exit(EXIT_FAILURE);
    }
}

int
main(int argc, const char *argv[])
{
    int i;

    if (argc < 2)
    {
        printf("%s <file1> <file2>...\n", argv[0]);
        exit(0);
    }

    for(i = 1; i < argc; i++)
    {
        seek_filesize(argv[i]);
        stat_filesize(argv[i]);
        fstat_filesize(argv[i]);
        fseek_filesize(argv[i]);
    }

    return 0;
}
  • 0
    или if(off == (-1L)) нет необходимости (long)
-34
#include <stdio.h>

#define MAXNUMBER 1024

int main()
{
    int i;
    char a[MAXNUMBER];

    FILE *fp = popen("du -b  /bin/bash", "r");

    while((a[i++] = getc(fp))!= 9)
        ;

    a[i] ='\0';

    printf(" a is %s\n", a);

    pclose(fp);
    return 0;
}  

НТН

  • 18
    Это решение просто излишне сложное и неэффективное. Нет необходимости выполнять команду и анализировать ее вывод, как ясно из ответов выше.
  • 3
    Кроме того, это решение только для Linux

Ещё вопросы

Сообщество Overcoder
Наверх
Меню