你如何确定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
!
请注意:文件可以在fsize
和read
之间增长。小心。
【参考方案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 这样的东西。 #includeMatt 的解决方案应该可以工作,只是它是 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 文件,并且可能比仅使用特定于平台的调用(如 GetFileSizeEx
或 stat64
)要慢。
【讨论】:
是的,你应该这样做。但是,除非有一个非常令人信服的理由不编写特定于平台的代码,否则您可能应该只使用特定于平台的调用而不是 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 报告完全是错误的。fseeko
和 ftello
(或者 fseek
和 ftell
,如果你没有前者并且对可以使用的文件大小的限制感到满意)是确定文件长度的正确方法。基于stat
的解决方案不适用于许多“文件”(例如块设备),并且不能移植到非 POSIX 系统。
这是在许多非 posix 兼容系统(例如我的极简 mbed)上获取文件大小的唯一方法
你绝对不想在这里使用int
。 ftell
返回一个有符号的long
,它在许多(但不是全部)64 位系统上是一个 64 位类型。在大多数 32 位系统上它仍然只有 32 位,因此您需要 ftello
和 off_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 标准,并在二进制流中将 fseek
到 SEEK_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 不起作用。 如果文件是管道,它将返回0
或stdin
。意见: 您应该改用 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中文件的大小?的主要内容,如果未能解决你的问题,请参考以下文章