当前位置:  开发笔记 > 编程语言 > 正文

如何在C中获取文件大小?

如何解决《如何在C中获取文件大小?》经验,为你挑选了7个好方法。

您需要寻找文件的末尾然后询问位置:

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

然后你可以回头,例如:

fseek(fp, 0L, SEEK_SET);

或者(如果想要开始)

rewind(fp);

返回有符号的int,因此限制为2 GB.但从好的方面来说,你的文件可能是20亿字节的负数,并且他们已为此做好准备. (98认同)

呃,在人们忘记它意味着什么之前,先使用[`rewind`](http://www.cplusplus.com/reference/clibrary/cstdio/rewind/) (59认同)

来自[fseek documentation](http://www.cplusplus.com/reference/cstdio/fseek/)"允许库实现无意义地支持SEEK_END(因此,使用它的代码没有真正的标准可移植性)." (21认同)

`length = lseek(fd,0,SEEK_END)+1;` (18认同)

@camh - 谢谢你.这个评论解决了我使用文件大小调整算法时遇到的问题.对于记录,通过在fopen的模式字符串的末尾加上'b',以二进制模式打开文件. (11认同)

这不是便携式的.不要使用这个.它不符合POSIX标准 (6认同)

大声笑,是的,Windows从DOS继承了这种愚蠢的文本/二进制模式废话.现在很容易忘记这一点.实际上POSIX标准甚至要求任何POSIX系统必须能够处理fopen调用中的"b"标志(与C标准兼容!),但同时它要求,实现必须完全忽略它,因为这个标志对POSIX系统没有影响(那些人不知道文本模式这样的东西,总是以二进制模式打开). (4认同)

使用fseeko和ftello可以避免> 2GB的概率.如果可能的话编辑答案.!! (2认同)

@RobWalker:https://www.securecoding.cert.org/confluence/display/c/FIO19-C.+Do+not+use+fseek()+and+ftell()+to+compute+the+size+ + A +常规+文件 (2认同)


Greg Hewgill.. 360

使用标准库:

假设您的实现有意义地支持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 
struct stat st;
stat(filename, &st);
size = st.st_size;

Win32的:

您可以使用GetFileSize或GetFileSizeEx.



1> Rob Walker..:

您需要寻找文件的末尾然后询问位置:

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

然后你可以回头,例如:

fseek(fp, 0L, SEEK_SET);

或者(如果想要开始)

rewind(fp);


返回有符号的int,因此限制为2 GB.但从好的方面来说,你的文件可能是20亿字节的负数,并且他们已为此做好准备.
呃,在人们忘记它意味着什么之前,先使用[`rewind`](http://www.cplusplus.com/reference/clibrary/cstdio/rewind/)
来自[fseek documentation](http://www.cplusplus.com/reference/cstdio/fseek/)"允许库实现无意义地支持SEEK_END(因此,使用它的代码没有真正的标准可移植性)."
`length = lseek(fd,0,SEEK_END)+1;`
@camh - 谢谢你.这个评论解决了我使用文件大小调整算法时遇到的问题.对于记录,通过在fopen的模式字符串的末尾加上'b',以二进制模式打开文件.
这不是便携式的.不要使用这个.它不符合POSIX标准
大声笑,是的,Windows从DOS继承了这种愚蠢的文本/二进制模式废话.现在很容易忘记这一点.实际上POSIX标准甚至要求任何POSIX系统必须能够处理fopen调用中的"b"标志(与C标准兼容!),但同时它要求,实现必须完全忽略它,因为这个标志对POSIX系统没有影响(那些人不知道文本模式这样的东西,总是以二进制模式打开).
使用fseeko和ftello可以避免> 2GB的概率.如果可能的话编辑答案.!!
@RobWalker:https://www.securecoding.cert.org/confluence/display/c/FIO19-C.+Do+not+use+fseek()+and+ftell()+to+compute+the+size+ + A +常规+文件

2> Greg Hewgill..:

使用标准库:

假设您的实现有意义地支持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 
struct stat st;
stat(filename, &st);
size = st.st_size;

Win32的:

您可以使用GetFileSize或GetFileSizeEx.


您不需要文件名 - 您可以使用fstat.
请注意,为了清楚起见,我省略了错误检查.
第二个选项是唯一可以显示大于2GB的文件大小的选项
为了-FATAL ERROR,EXITING的利益,我省略了错误检查.
您需要指定stat的结构地址.第二行应该是:stat(filename,&st);
用fseeko和ftello取代fseek和ftell.然后它适用于大于2 GB的文件.. !!
也可以使用倒带(f)将文件指针移回文件的开头

3> PiedPiper..:

如果您有文件描述符 fstat()返回包含文件大小的stat结构.

#include 
#include 
#include 

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


当然它需要错误检查 - 这会使示例复杂化.
很多SO的用户都是C的学生,而不是过去的大师.因此,答案中给出的代码应显示错误检查,以便学生学习正确的编码方式.
这在我看来是最好的答案,而且我认为我们在C中大部分时间都有训练轮,我们真的需要在我们的例子中进行错误检查和其他不必要的代码,它足够糟糕的M $ DN在他们不要跟风,而只是说最后'确保添加错误检查'并完成它.
有一个细节,(f)stat()返回块分配总字节,而fseek()/ ftell()序列返回遇到EOF之前的字节数.
添加"fd = fileno(f);" 如果你有一个流(例如来自fopen),而不是文件描述符.需要错误检查.

4> Earlz..:

我最后只是做了一个简短而有趣的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)



5> 小智..:

如何使用lseek / fseek / stat / fstat获取文件大小?

#include 
#include 
#include 
#include 
#include 


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  ...\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;
}



6> 小智..:

您是否考虑过不计算文件大小而只是在必要时增加数组?这是一个例子(省略错误检查):

#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)也能工作.


也许可以在这里使用`realloc`函数而不是使用中间指针并且必须使用`free()`.
除非我误读,否则每次都会将大小存储为双打.因此,运行时间是O(n)而不是O(n ^ 2).这与通常用于std :: vector及其类似的分配策略相同.无论如何,重新分配仍然不如查询文件大小和一次读取所有内容.

7> Ben Combee..:

如果您使用的是Linux,请认真考虑使用glib中的g_file_get_contents函数.它处理加载文件,分配内存和处理错误的所有代码.


如果您使用的是Linux*并且*希望依赖glib,那就是.
@DaveAppleton:不,glib是一个简单的C库,而不是C++.
问题并不是那么糟糕,因为现在GTK和KDE应用程序都使用了glib.它也适用于Mac OS X和Windows,但它并不像那里那么标准.
推荐阅读
coco2冰冰
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有