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

Posted

技术标签:

【中文标题】你如何确定C中文件的大小?【英文标题】:How do you determine the size of a file in C? 【发布时间】:2010-09-05 17:06:51 【问题描述】:

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

#include <stdio.h>

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

【问题讨论】:

您将需要使用库函数来检索文件的详细信息。由于 C 完全独立于平台,因此您需要让我们知道您正在开发的平台/操作系统! 为什么是char* file,为什么不是FILE* file? -1 @user12211554 这样...就strlen! 请注意:文件可以在fsizeread 之间增长。小心。 【参考方案1】:

如果您对使用 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 标准。【参考方案2】:

您可以打开文件,使用

转到相对于文件底部的 0 偏移量
#define SEEKBOTTOM   2

fseek(handle, 0, SEEKBOTTOM)  

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

我很久没有用 C 写代码了,但我认为它应该可以工作。

【讨论】:

你不应该定义像 SEEKBOTTOM 这样的东西。 #include fseek(handle, 0, SEEK_END);【参考方案3】:

Matt 的解决方案应该可以工作,只是它是 C++ 而不是 C,而且不需要最初的 tell。

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 文件,并且可能比仅使用特定于平台的调用(如 GetFileSizeExstat64)要慢。

【讨论】:

是的,你应该这样做。但是,除非有一个非常令人信服的理由不编写特定于平台的代码,否则您可能应该只使用特定于平台的调用而不是 open/seek-end/tell/close 模式。 很抱歉回复晚了,但我在这里遇到了一个大问题。它会导致应用程序在访问受限文件(如密码保护或系统文件)时挂起。有没有办法在需要时向用户询问密码? @Justin,您可能应该专门针对您遇到的问题提出一个新问题,并提供有关您所在平台的详细信息,您如何访问文件,以及行为是。 C99 和 C11 都从 ftell() 返回 long int(unsigned long) 转换不会提高范围,因为它已经受到功能的限制。 ftell() 出错时返回 -1 并且与演员表混淆。建议fsize()返回与ftell()相同的类型。 我同意。演员阵容是为了匹配问题中的原始原型。不过,我不记得为什么我把它变成了 unsigned long 而不是 unsigned int。【参考方案4】:

**不要这样做(why?):

引用我在网上找到的 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

【讨论】:

@mezhaka:CERT 报告完全是错误的。 fseekoftello(或者 fseekftell,如果你没有前者并且对可以使用的文件大小的限制感到满意)是确定文件长度的正确方法。基于stat 的解决方案不适用于许多“文件”(例如块设备),并且不能移植到非 POSIX 系统。 这是在许多非 posix 兼容系统(例如我的极简 mbed)上获取文件大小的唯一方法 你绝对不想在这里使用intftell 返回一个有符号的long,它在许多(但不是全部)64 位系统上是一个 64 位类型。在大多数 32 位系统上它仍然只有 32 位,因此您需要 ftellooff_t 才能便携地处理大文件。尽管 ISO C 选择不定义行为,但大多数实现都会这样做,因此这在大多数系统上确实有效。【参考方案5】:

我找到了a method using fseek and ftell 和一个带有这个问题的线程,其中的答案是不能以其他方式仅在 C 中完成。

您可以使用像 NSPR(支持 Firefox 的库)这样的可移植库。

【讨论】:

【参考方案6】:

不要使用int。如今,大小超过 2 GB 的文件很常见

不要使用unsigned int。大小超过 4 GB 的文件很常见,因为有些不太常见

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

如果你在 Windows 上,你应该使用GetFileSizeEx - 它实际上使用一个有符号的 64 位整数,所以他们会开始遇到 8 艾字节文件的问题。愚蠢的微软! :-)

【讨论】:

我使用了 off_t 为 32 位的编译器。当然,这是在 4GB 文件不太常见的嵌入式系统上。无论如何,POSIX 还定义了 off64_t 和相应的方法来增加混乱。 我总是喜欢假设 Windows 的答案,除了批评这个问题什么都不做。您能否添加一些符合 POSIX 的内容? @JL2210 Ted Percival 接受的答案显示了一个符合 posix 的解决方案,所以我认为重复显而易见的事情没有任何意义。我(和其他 70 人)认为添加关于 windows 的注释而不使用带符号的 32 位整数来表示文件大小是最重要的增值。干杯【参考方案7】:

如果您正在构建 Windows 应用程序,请使用 GetFileSizeEx API,因为 CRT 文件 I/O 很混乱,尤其是在确定文件长度时,由于不同系统上文件表示的特殊性;)

【讨论】:

【参考方案8】:

在类 Unix 系统上,您可以在已打开的文件描述符(POSIX man page、Linux man page)上使用 POSIX 系统调用:stat on a path 或 fstat。 (从open(2)fileno(FILE*) 获取stdio 流上的文件描述符)。

基于 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 GB 的值。有关详细信息,请参阅Large File Support in Linux 的“使用 LFS”部分。

【讨论】:

这是 Linux/Unix 特有的——可能值得指出,因为问题没有指定操作系统。 您可以将返回类型更改为 ssize_t 并从 off_t 转换大小而不会遇到任何问题。使用 ssize_t 似乎更有意义 :-) (不要与未签名且不能用于指示错误的 size_t 混淆。) 如需更便携的代码,请使用 Derek 建议的fseek + ftell 如需更便携的代码,请使用 Derek 建议的 fseek + ftell 不,C Standard 明确指出 fseek()SEEK_END on二进制文件是未定义的行为。 7.19.9.2 fseek 函数 ...二进制流不需要有意义地支持 fseek 调用的 wherece 值为 SEEK_END,如下所述,来自第 234 页的脚注。 267 的链接 C 标准,并在二进制流中将 fseekSEEK_END 专门标记为未定义的行为。 . 来自gnu libc manual: ... [非POSIX] 系统区分包含文本的文件和包含二进制数据的文件,ISO C 的输入和输出工具提供了这种区分。 ...在 GNU C 库和所有 POSIX 系统中,文本流和二进制流之间没有区别。当您打开一个流时,无论您是否要求二进制,您都会得到相同类型的流。此流可以处理任何文件内容,并且没有文本流有时具有的限制。【参考方案9】:

我用这组代码求文件长度。

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

【讨论】:

【参考方案10】:

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

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 

【讨论】:

不需要关闭文件吗? 不,我不喜欢需要路径的函数。相反,请让 ti 期望一个文件指针 如果您在 Windows 上运行并且文件大小为 14 GB,会发生什么? @AndrewHenle:在这种情况下,您需要使用ftello,它返回一个off_t,即使long 不是,它也可以是64 位类型。我假设ftello 在理论上仍然存在与您描述的in an answer 相同的问题,即寻求二进制流末尾的未定义行为,但是 ISO C 没有提供更好的 AFAIK,所以对于很多程序来说至少- 坏事是依赖实现来定义这种行为。 @PeterCordes Windows uses _ftelli64()(什么?!?微软使用了不可移植的功能?在某种程度上导致供应商锁定?!!?说不是这样!)但如果你'依赖于实现定义的行为,您不妨使用实现的方法来获取文件大小。 fileno()stat() 在 Windows 上均受支持,尽管在供应商锁定模式下为 _fileno()_fstat()#ifdef _WIN32 #define fstat _fstat #define fileno _fileno #endif 实际上是最便携的解决方案。【参考方案11】:

试试这个 --

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

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

file_size 包含文件包含的字节数。请注意,由于(根据 climits.h)unsigned long 类型被限制为 4294967295 字节(4 GB),如果您可能要处理比这更大的文件,则需要找到不同的变量类型。

【讨论】:

这与 8 年前的 Derek's answer 有什么不同? 对于二进制流,这是未定义的行为,对于文本流ftell 不会返回代表可以从文件中读取的字节数的值。【参考方案12】:

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 不直接提供确定文件长度的方法。 我们将不得不使用我们的头脑。现在,我们将使用 seek 方法!

概要

使用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);

如果文件是stdin 或管道。 POSIX、ANSI C 不起作用。 如果文件是管道,它将返回 0stdin

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

【讨论】:

struct _stat64__stat64() 用于 _Windows。 最后一个例子不正确,fopen 有两个参数【参考方案13】:

我有一个只适用于stdio.h 的函数。我非常喜欢它,而且效果很好而且非常简洁:

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

【讨论】:

【参考方案14】:

C++ MFC 从 windows 文件详细信息中提取,不确定这是否比 seek 性能更好,但如果从元数据中提取,我认为它更快,因为它不需要读取整个文件

ULONGLONG GetFileSizeAtt(const wchar_t *wFile)

    WIN32_FILE_ATTRIBUTE_DATA fileInfo;
    ULONGLONG FileSize = 0ULL;
    //https://docs.microsoft.com/nl-nl/windows/win32/api/fileapi/nf-fileapi-getfileattributesexa?redirectedfrom=MSDN
    //https://docs.microsoft.com/nl-nl/windows/win32/api/fileapi/ns-fileapi-win32_file_attribute_data?redirectedfrom=MSDN
    if (GetFileAttributesEx(wFile, GetFileExInfoStandard, &fileInfo))
    
        ULARGE_INTEGER ul;
        ul.HighPart = fileInfo.nFileSizeHigh;
        ul.LowPart = fileInfo.nFileSizeLow;
        FileSize = ul.QuadPart;
    
    return FileSize;

【讨论】:

以上是关于你如何确定C中文件的大小?的主要内容,如果未能解决你的问题,请参考以下文章

c语言中,系统为结构类型变量所分配的内存空间大小如何确定?

如何修改ubuntu虚拟机内存大小

C语言中如何改变字体大小和颜色?

C语言中如何改变字体大小和颜色?

PROTEL 99SE 中如何确定PCB板的形状和大小

使用 C:如何确定浮点组件的大小?