您如何确定C中文件的大小?


137

如何计算文件大小(以字节为单位)?

#include <stdio.h>

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

您将需要使用库函数来检索文件的详细信息。由于C完全独立于平台,因此您需要让我们知道您要开发的平台/操作系统!
克里斯·罗伯茨

为什么char* file,为什么不FILE* file呢?-1
奥斯卡先生

-1因为文件功能应该接受文件描述符而不是文件路径
Oscar先生,

Answers:


144

基于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; 
}

变化:

  • 将filename参数设为a 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位系统上,应使用option进行编译-D_FILE_OFFSET_BITS=64,否则off_t只能保存最大2 GB的值。有关详细信息,请参见Linux大文件支持的“使用LFS”部分。


19
这是特定于Linux / Unix的-可能值得指出,因为问题未指定操作系统。
德鲁·霍尔

1
您可以将返回类型更改为ssize_t并从off_t强制转换大小,而不会遇到任何麻烦。使用ssize_t :-)似乎更有意义(不要与未签名的size_t混淆,并且不能用来表示错误。)
Ted Percival 2010年

1
要获得更多可移植的代码,请使用Derek建议的fseek+ ftell
西罗Santilli郝海东冠状病六四事件法轮功

9
要获得更多可移植的代码,请使用Derek建议的fseek+ ftell 号的C标准明确规定,fseek()SEEK_END一个二进制文件的是未定义的行为。 7.19.9.2 fseek函数 ...二进制流不必有意义地支持fseekwhence值为SEEK_END和的调用,如下所述(来自p的脚注234)。链接的C标准,并且其特异性标签267 fseekSEEK_END在二进制流作为未定义的行为。。
Andrew Henle

74

不要使用int。如今,超过2 GB的文件通常很脏

不要使用unsigned int。大小超过4 GB的文件很常见,是一些不太常见的污垢

IIRC标准库将其定义off_t为无符号的64位整数,这是每个人都应使用的整数。几年后,当我们开始挂起16 EB文件时,我们可以将其重新定义为128位。

如果您使用的是Windows,则应使用GetFileSizeEx-它实际上使用带符号的64位整数,因此它们将开始遇到8艾字节文件的问题。愚蠢的微软!:-)


1
我使用过off_t是32位的编译器。当然,这是在较少使用4GB文件的嵌入式系统上。无论如何,POSIX还定义了off64_t和相应的方法来增加混乱。
亚伦·坎贝尔

我一直喜欢假定Windows的答案,除了批评这个问题外别无所求。您能否添加兼容POSIX的内容?
SS安妮

1
@ JL2210 Ted Percival接受的答案显示了posix兼容的解决方案,因此我认为重复显而易见的做法没有任何意义。我(和其他70个人)认为,添加关于Windows的注释,而不是使用带符号的32位整数表示文件大小,是最重要的附加值。欢呼声
Orion Edwards,

30

Matt的解决方案应该可以用,除了它是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上它仅限于4GB的文件,并且可能比仅使用特定于平台的调用(例如GetFileSizeEx或)要慢stat64


是的你应该。但是,除非有确凿的理由不编写特定于平台的代码,否则您可能应该只使用特定于平台的调用,而不要使用open / seek-end / tell / close模式。
Derek Park

1
抱歉,回复晚了,但我在这里遇到了重大问题。当访问受限制的文件(例如受密码保护的文件或系统文件)时,它会使应用程序挂起。是否可以在需要时询问用户密码?
贾斯汀

@Justin,您可能应该专门针对所遇到的问题打开一个新问题,并提供有关所用平台,如何访问文件以及行为的详细信息。
Derek Park

1
C99和C11都long int从返回ftell()(unsigned long)强制转换不能改善范围,因为功能已经限制了该范围。 ftell()传回-1时发生错误,并且会因转换而混淆。建议fsize()返回与相同的类型ftell()
chux-恢复莫妮卡2014年

我同意。演员表要与问题中的原始原型相匹配。我不记得为什么将它变成unsigned long而不是unsigned int。
德里克·帕克

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
}

5
@mezhaka:该CERT报告简直是错误的。fseekoftello(或者fseekftell如果您没有前者而感到困惑,并且对可以使用的文件大小的限制感到满意)是确定文件长度的正确方法。stat基于解决方案的解决方案不能在许多“文件”(例如块设备)上运行,并且不能移植到非POSIX的系统上。
R .. GitHub停止帮助ICE,2010年

1
这是在许多非posix兼容系统(例如我的极简mbed)上获取文件大小的唯一方法
Earlz 2012年

9

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不直接提供,以确定文件的长度的方式。
我们必须要动脑子。现在,我们将使用搜索方法!

概要

#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无法正常工作。 如果文件是管道或
,它将返回。0stdin

意见:您应该改用POSIX标准。因为,它具有64位支持。


1
struct _stat64__stat64()对于_WINDOWS。
鲍勃·斯坦

5

而且,如果您要构建Windows应用程序,请使用GetFileSizeEx API,因为CRT文件的I / O杂乱无章,特别是对于确定文件长度,由于不同系统上文件表示的特殊性;)


5

如果您可以使用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;
}

24
那不是标准C。它是POSIX标准的一部分,但不是C标准。
德里克公园

3

在Google中进行的快速搜索找到了使用fseek和ftell的方法以及一个带有此问题的线程,并给出了答案,它不能用另一种方式仅用C来完成。

您可以使用可移植性库,例如NSPR(为Firefox提供支持的库),也可以检查其实现(相当麻烦)。


1

我使用这组代码来查找文件长度。

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

试试这个 -

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

首先,寻找文件的结尾;然后,报告文件指针的位置。最后(这是可选的),它后退到文件的开头。注意,它fp应该是一个二进制流。

file_size包含文件包含的字节数。请注意,由于(根据climits.h)无符号长类型限制为4294967295字节(4 GB),因此,如果您可能要处理更大的文件,则需要查找其他变量类型。


3
这与8年前的德里克(Derek)的答案有何不同?
PP

对于二进制流,这是未定义的行为,对于文本流,ftell它不返回表示可以从文件读取的字节数的值。
Andrew Henle

0

我有一个仅适用于的功能stdio.h。我非常喜欢它,并且效果很好,非常简洁:

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

0

这是一个简单干净的函数,用于返回文件大小。

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 
}

1
您不需要关闭文件吗?
杰里·耶利米

不,我不喜欢期望路径的功能。相反,请使ti成为文件指针
Oscar先生

-3

您可以打开文件,使用以下命令将文件底部相对于偏移量设置为0

#define SEEKBOTTOM   2

fseek(handle, 0, SEEKBOTTOM)  

从fseek返回的值是文件的大小。

我很长时间没有用C编写代码,但是我认为它应该可以工作。


12
您不必定义诸如SEEKBOTTOM之类的东西。#include <stdio.h> fseek(handle,0,SEEK_END);
sigjuice

-4

看问题,ftell可以很容易地得到字节数。

  long size = ftell(FILENAME);
  printf("total size is %ld bytes",size);

ftell需要文件描述符而不是文件名作为参数。
Barmar

@Barmar,否ftell不期望文件描述符,而是期望一个文件描述符FILE*。请先参见手册页!

这种方法是完全错误的,每次ftell都会返回的常量0

这个答案是绝对错误的,至于,您fseek()首先需要使用它来寻找文件的结尾,并且还ftell()期望使用FILE *,而不是字符串!您将很乐意充实您的答案。
奥斯卡先生
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.