导读:本期聚焦于霓渡创作的《C++中如何用stat函数获取文件大小?关键技巧与示例详解》,敬请观看详情。同样是读取文件大小,用ifstream先把文件打开再seekg到末尾,不仅会改变流状态,在文本模式下还可能因换行转换得到错误数值。stat函数不需要打开文件,直接查询目录元数据,返回struct stat中的st_size字段,适合普通文件和批量检测。本文从stat、fstat、lstat三个函数切入,说明如何通过S_ISREG判断文件类型,如何用errno处理ENOENT和EACCES,并对比32位与64位下off_t的差异。再结合Windows中的_stat64和C++17的std::filesystem::file_size,给出跨平台建议。文中包含可直接编译的运行示例,也会指出符号链接、管道文件、proc虚拟文件的特殊表现。

获取文件大小这个操作在日常开发中出现的频率很高,但真正可靠的实现并不是只有一种。C++标准库没有直接提供获取文件字节数的函数,在POSIX环境中stat系统调用通常是首选。它通过路径直接读取文件在文件系统中的元数据,不需要打开文件、读取内容或移动文件指针,因此不会干扰其他读写操作。调用成功时,stat会把包括权限、时间戳、大小在内的信息写入一个struct stat结构体,其中st_size字段就是普通文件大小。下面逐步拆解stat的用法和几个容易忽略的技巧。

C++中如何用stat函数获取文件大小?关键技巧与示例详解

stat的工作机制与核心结构体

stat函数声明在<sys/stat.h>头文件中,原型为int stat(const char *pathname, struct stat *statbuf);。它接收两个参数:目标路径和指向struct stat的指针。执行成功后返回0,失败返回-1并设置errno。常见错误码包括ENOENT表示路径不存在,EACCES表示权限不足,ENOTDIR表示路径前缀不是目录。

struct stat里最重要的是st_mode和st_size。st_mode保存文件类型和权限位,使用S_ISREG(info.st_mode)可以判断目标是否为普通文件。st_size的类型是off_t,在64位Linux下通常为64位有符号整数,能表示超大文件;但在32位平台可能只有32位,超过约2GB会出现截断。解决办法是编译时定义_FILE_OFFSET_BITS=64,让off_t升级为64位。

另一个要区分的概念是逻辑大小与磁盘占用。st_size反映的是文件内容字节数,不包含文件系统为存储该文件额外分配的块或元数据;要查看实际占用可以用st_blocks字段乘以512。对于稀疏文件,两者差异可能很大,这也是stat比遍历内容更直观的原因之一。

用stat获取文件大小的完整示例与错误处理

下面是一个封装好的函数,接收路径参数并输出错误原因。先判断stat调用是否成功,再确认目标是普通文件,最后安全转换成long long返回。错误信息通过strerror输出,比直接打印错误码更直观。

#include <sys/stat.h>
#include <iostream>
#include <cerrno>
#include <cstring>

bool getFileSize(const char* path, long long& size) {
    struct stat info;
    if (stat(path, &info) != 0) {
        std::cerr << "stat failed: " << std::strerror(errno) << "\n";
        return false;
    }
    if (!S_ISREG(info.st_mode)) {
        std::cerr << "not a regular file\n";
        return false;
    }
    size = static_cast<long long>(info.st_size);
    return true;
}

错误处理不能只判断返回值非0就结束。例如路径不存在、权限不足、目录前缀错误,对应的处理策略完全不同。在记录日志时建议同时保留errno和路径参数,方便线上排查。C++程序里errno是线程本地变量,多线程环境下不会互相污染,但必须在调用失败后立刻读取,否则后续库函数可能覆盖它。

如果希望接口更现代,可以返回std::optional<long long>,用空值表示失败。转换大文件大小时使用static_cast而不是隐式转换,既避免警告,也让类型意图更清晰。对于只读检测,stat不要求文件可读权限,只要路径所在目录有执行权限即可获取元数据。

fstat与lstat:处理已打开文件与符号链接

如果文件已经被程序打开,或只想获取已打开文件的属性,可以使用fstat(int fd, struct stat *buf)。它与stat的区别是第一个参数换成文件描述符。这样能避免路径在检查期间被替换或删除的竞态问题。比如先open得到fd,再用fstat读取大小,然后继续读写,整个过程指向同一个打开文件。

符号链接则更微妙。stat会跟踪符号链接并返回目标文件的信息,而lstat返回链接文件本身的信息。如果只想判断某个路径是否是符号链接以及链接本身大小,可以用S_ISLNK(info.st_mode)配合lstat。在清理目录或做安全检查时,这个差别会直接影响判断结果。

下面的示例分别用lstat检查链接,再用stat获取目标文件大小:

#include <sys/stat.h>
#include <iostream>

void checkLink(const char* path) {
    struct stat info;
    if (lstat(path, &info) == 0 && S_ISLNK(info.st_mode)) {
        std::cout << path << " is a symbolic link\n";
    } else if (stat(path, &info) == 0 && S_ISREG(info.st_mode)) {
        std::cout << "target size: " << info.st_size << "\n";
    }
}

要注意lstat自己的st_size对于符号链接表示的是链接路径字符串长度,而不是目标文件大小。如果业务需要目标文件大小,仍应使用stat。在目录遍历中同时使用两个函数,可以避免把符号链接误判为普通文件。

跨平台注意与现代替代方案

Windows环境下没有POSIX的stat,但MSVC提供了兼容函数_stat和_stat64,头文件为<sys/stat.h>或<sys/types.h>。其中_stat64的st_size是__int64类型,适合大文件。Linux和macOS还可以直接用stat64变体,但在64位系统上通常与stat等价。跨平台项目可以用条件编译封装一层接口。

如果项目使用C++17或更高版本,标准库提供了std::filesystem::file_size。它封装了不同平台的系统调用,返回std::uintmax_t,使用起来更简单。但在某些旧编译器或受限环境下可能不可用,而且它会抛出std::filesystem::filesystem_error,错误处理方式与errno不同。理解底层stat仍然有助于排查问题。

最后要提醒一个常见误区:不要依赖st_size来读取特殊文件。对管道、套接字或/proc下的虚拟文件,st_size可能为0或动态变化,但实际可以读取到数据。此时应当用循环读取直到EOF来确定字节数。判断普通文件是保证结果准确的前提。

C++获取文件大小stat函数struct stat修改时间:2026-09-24 07:08:30

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/0924/61220.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。