提问人:andrewrk 提问时间:8/12/2008 最后编辑:hippietrailandrewrk 更新时间:1/7/2023 访问量:155103
你如何确定 C 语言中文件的大小?
How do you determine the size of a file in C?
问:
如何计算文件的大小(以字节为单位)?
#include <stdio.h>
unsigned int fsize(char* file){
//what goes here?
}
答:
如果您对使用 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;
}
评论
您可以打开文件,从文件底部转到 0 偏移量
#define SEEKBOTTOM 2
fseek(handle, 0, SEEKBOTTOM)
从 fseek 返回的值是文件的大小。
我已经很久没有用 C 编写代码了,但我认为它应该有效。
评论
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
评论
long int
ftell()
(unsigned long)
ftell()
fsize()
ftell()
int
long
ftello
off_t
**不要这样做(为什么?
引用我在网上找到的 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
}
评论
fseeko
ftello
fseek
ftell
stat
int
ftell
long
ftello
off_t
我找到了一种使用 fseek 和 ftell 的方法,以及一个带有这个问题的线程,其答案是它不能以另一种方式在 C 中完成。
您可以使用像 NSPR(支持 Firefox 的库)这样的可移植性库。
不要使用 .如今,大小超过 2 GB 的文件很常见int
不要使用 .大小超过 4 GB 的文件很常见,因为一些不太常见的污垢unsigned int
IIRC 标准库定义为无符号 64 位整数,这是每个人都应该使用的。我们可以在几年内将其重新定义为 128 位,当我们开始有 16 EB 文件挂在身边时。off_t
如果你使用的是 Windows,你应该使用 GetFileSizeEx - 它实际上使用一个有符号的 64 位整数,所以他们会开始遇到 8 EB 文件的问题。愚蠢的Microsoft!:-)
评论
如果要生成 Windows 应用,请使用 GetFileSizeEx API,因为 CRT 文件 I/O 很混乱,尤其是在确定文件长度时,这是由于不同系统上的文件表示形式的特殊性;)
在类 Unix 系统上,您可以在路径上或已打开的文件描述符(POSIX 手册页、Linux 手册页)上使用 POSIX 系统调用:stat。
(从 或 stdio 流中获取文件描述符)。fstat
open(2)
fileno(FILE*)
基于 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
- Error 时返回,而不是 ,这对于空文件来说是不明确的。 是有符号类型,因此这是可能的。
-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 位系统上,您应该使用选项进行编译,否则最多只能保存 2 GB 的值。有关详细信息,请参阅 Linux 中的大文件支持的“使用 LFS”部分。-D_FILE_OFFSET_BITS=64
off_t
评论
fseek
ftell
fseek
+ ftell
。不。C 标准明确指出,在二进制文件上是未定义的行为。7.19.9.2 fseek
函数 ...二进制流不需要有意义地支持值为 SEEK_END
的 fseek
调用,如下所述,该调用来自链接的 C 标准第 267 页的脚注 234,并且专门将二进制流中的 to 标记为未定义的行为。.fseek()
SEEK_END
fseek
SEEK_END
我使用这组代码来查找文件长度。
//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);
评论
下面是一个简单而干净的函数,用于返回文件大小。
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 size;
}
评论
ftell
对于文本文件,可能不是字节偏移量(在文本模式下打开文件)
ftello
off_t
long
ftello
_ftelli64() (
什么?!?Microsoft 使用不可移植功能?在某种程度上导致供应商锁定?!!?说不是这样!但是,如果您依赖于实现定义的行为,则不妨使用实现的方法来获取文件大小。两者在 Windows 上都受支持,尽管在供应商锁定模式下为 和 。 实际上是最便携的解决方案。fileno()
stat()
_fileno()
_fstat()
#ifdef _WIN32 #define fstat _fstat #define fileno _fileno #endif
POSIX的
POSIX 标准有自己的方法来获取文件大小。
包含标头以使用该函数。sys/stat.h
概要
- 使用
stat(3)
获取文件统计信息。 - 获取属性。
st_size
例子
注意:它将大小限制为 。如果不是文件系统,请使用 64 位版本!4GB
Fat32
#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);
}
如果文件是 或 管道。POSIX、ANSI C 不起作用。
如果文件是管道或 ,它将返回。stdin
0
stdin
意见: 您应该改用 POSIX 标准。因为,它有 64 位支持。
评论
struct _stat64
和_Windows。__stat64()
fopen
ftell
只能保证从文件开头开始的字节数。但是,在文本模式下,返回的值未指定,并且仅对 有意义。ftell
fseek
我有一个功能,只能很好地工作.我非常喜欢它,它运行良好且非常简洁:stdio.h
size_t fsize(FILE *File) {
size_t FSZ;
fseek(File, 0, 2);
FSZ = ftell(File);
rewind(File);
return FSZ;
}
从Windows文件详细信息中提取的C++ MFC,不确定这是否比搜索性能更好,但如果它是从元数据中提取的,我认为它更快,因为它不需要读取整个文件
ULONGLONG GetFileSizeAtt(const wchar_t *wFile)
{
WIN32_FILE_ATTRIBUTE_DATA fileInfo;
ULONGLONG FileSize = 0ULL;
//https://learn.microsoft.com/nl-nl/windows/win32/api/fileapi/nf-fileapi-getfileattributesexa?redirectedfrom=MSDN
//https://learn.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;
}
在普通的 ISO C 中,只有一种方法可以确定文件的大小,并保证有效:从头开始读取整个文件,直到遇到文件末尾。
然而,这是非常低效的。如果您想要一个更有效的解决方案,那么您将不得不
- 依赖于特定于平台的行为,或者
- 还原为特定于平台的函数,例如 Linux 上的
stat
或 Microsoft Windows 上的GetFileSize
。
与其他答案所建议的相反,以下代码不能保证有效:
fseek( fp, 0, SEEK_END );
long size = ftell( fp );
即使我们假设数据类型足够大来表示文件大小(这在某些平台上是有问题的,尤其是 Microsoft Windows),发布的代码也存在以下问题:long
发布的代码不能保证在文本流上工作,因为根据 ISO C11 标准的 §7.21.9.4 ¶2,返回的文件位置指示器的值包含未指定的信息。只有对于二进制流,此值才能保证为从文件开头开始的字符数。文本流没有这样的保证。ftell
发布的代码也不能保证在二进制流上工作,因为根据 ISO C11 标准的 §7.21.9.2 ¶3,二进制流不需要有意义地支持 .SEEK_END
话虽如此,在大多数常见的平台上,如果我们假设数据类型足够大以表示文件大小,则发布的代码将起作用。long
但是,在 Microsoft Windows 上,字符(回车符后跟换行符)将转换为文本流(但不用于二进制流),因此您获得的文件大小将计为两个字节,尽管您在文本模式下只读取单个字符 ()。因此,您获得的结果将不一致。\r\n
\n
\r\n
\n
在基于 POSIX 的平台(例如 Linux)上,这不是问题,因为在这些平台上,文本模式和二进制模式之间没有区别。
评论
long
ftell()
评论
char* file
FILE* file
strlen
fsize
read