English 中文(简体)
如何在C中获取文件大小? [重复]
原标题:
  • 时间:2008-10-26 20:54:57
  •  标签:

我该如何确定使用C语言编写的应用程序打开的文件的大小?

我想知道大小,因为我想把加载的文件内容放入一个字符串中,我使用malloc()分配字符串。

我认为仅仅写malloc(10000*sizeof(char));是一个坏主意。

最佳回答

你需要寻找文件的末尾,然后请求位置:

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

你可以回溯,例如:

fseek(fp, 0L, SEEK_SET);

或者(如果追求回到开始)

rewind(fp);
问题回答

Using standard library:

假定你的实现有实际意义地支持了 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(如果你有文件描述符)。

这里提供一个统计的例子:

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

Win32:

你可以使用 GetFileSizeGetFileSizeEx

如果您拥有文件描述符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;

我最后只是创建了一个简短而简洁的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

如何使用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
", filename);
        exit(EXIT_FAILURE);
    }

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

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

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

    if (fclose(fp) != 0)
    {
        printf("failed to fclose %s
", 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
", filename);
        exit(EXIT_FAILURE);
    }

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

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

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

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

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

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

}

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

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

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

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

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

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

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

    if (argc < 2)
    {
        printf("%s <file1> <file2>...
", 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;
}

你考虑过不计算文件大小,而只是在必要时扩大数组吗?这里是一个例子(省略了错误检查):

#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),它也可以工作。

如果你使用的是Linux操作系统,强烈建议使用glib的g_file_get_contents函数。它可以处理所有加载文件、分配内存和处理错误的代码。





相关问题
热门标签