在云服务器上用C语言读取文件大小,核心思路是“先让服务器确认文件在哪,再通过系统调用或依赖库拿到字节数”。本地Linux环境和云端远程路径的差异,往往是新手栽跟头的地方。
先分清你拿的是“本地文件”还是“远程文件”
云服务器上跑C程序,文件通常分两种情况,处理方式完全不同。
文件就在当前服务器的硬盘里
比如你用宝塔面板或SSH登录服务器,把图片上传到了 /www/wwwroot/site/uploads/ 目录,这个时候文件是服务器本地文件,C代码直接用 stat() 或 fseek() 就能搞定,这是最省事的状态,不存在网络请求,也不涉及协议。
文件在另一个存储节点上
比如你买了简米云OSS、酷番云COS,或者把文件放在另一台独立的数据服务器上,这时你的C程序只能通过HTTP或SDK访问远程资源,不能直接用文件路径,想拿大小,要么解析HTTP响应头里的 Content-Length,要么调用云厂商提供的SDK接口。
记住一个核心判断标准:能在服务器命令行里用 ls -l 看到的文件,走 stat();看不到的,走HTTP或SDK。
用 stat() 读取本地文件大小,最稳定的C语言方案
云服务器绝大多数是Linux系统,C语言标准库没有直接提供“获取文件大小”的函数,但POSIX标准下的 stat() 是行业通用做法。
#include <stdio.h>
#include <sys/stat.h>
int main() {
struct stat st;
const char path = "/www/wwwroot/site/uploads/demo.zip";
if (stat(path, &st) == 0) {
printf("文件大小: %lld 字节n", (long long)st.st_size);
} else {
perror("获取文件信息失败");
}
return 0;
}
注意 st_size 的类型,在64位Linux系统里,它是 off_t,本质是带符号的64位整数,用 %lld 配合 (long long) 强制转换,能避免在32位和64位环境间的编译警告。
编译时别忘加宏定义
处理大文件时(比如超过2GB的日志或备份包),编译命令需要指定:
gcc -D_FILE_OFFSET_BITS=64 -o get_size get_size.c
这是业内专家反复提醒过的坑,不加这个宏,32位环境下 off_t
只有32位,文件超过2GB就会溢出成负数。
open() 后配合 fstat() 更严谨
如果文件已经被你 open() 打开,用 fstat() 从文件描述符取信息,避免路径被篡改导致的竞态问题。
int fd = open(path, O_RDONLY);
struct stat st;
fstat(fd, &st);
printf("size = %lldn", (long long)st.st_size);
这种写法在处理动态写入的文件时更稳定,因为 fstat() 拿到的是“当前打开这个文件实例的大小”,不受后续路径重命名影响。
远程文件大小?先查 HTTP 的 Content-Length
很多云厂商的对象存储,比如简米云OSS的公共读文件、又拍云加速域名下的资源,本质都是通过HTTP对外暴露,C语言读取远程文件大小,最轻量的办法是发一个 HEAD 请求,不下载文件体,只看响应头。
用 libcurl 实现 HEAD 请求
libcurl 是Linux服务器上最常见的HTTP库,C语言项目里用它非常顺手。
#include <stdio.h>
#include <curl/curl.h>
size_t header_callback(char buffer, size_t size, size_t nitems, void userdata) {
size_t total = size nitems;
if (sscanf(buffer, "Content-Length: %lld", (long long)userdata) == 1) {
// 已读取到长度
}
return total;
}
int main() {
CURL curl = curl_easy_init();
long long file_size = -1;
curl_easy_setopt(curl, CURLOPT_URL, "https://your-bucket.oss-cn-hangzhou.aliyuncs.com/demo.zip");
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); // 不下载正文
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &file_size);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); // 跟随重定向
CURLcode res = curl_easy_perform(curl);
if (res == CURLE_OK && file_size > 0) {
printf("远程文件大小: %lld 字节n", file_size);
}
curl_easy_cleanup(curl);
return 0;
}
用 Linux 命令行先验证 URL
写C代码前,建议先在SSH终端里用 curl -I 看一眼:
curl -I https://your-bucket.oss-cn-hangzhou.aliyuncs.com/demo.zip
如果返回的HTTP状态码是 200 OK,而且响应头里有 Content-Length,说明远程文件可以正常访问,如果看到 403
或者 AccessDenied,C代码里再折腾也没用是权限或防盗链问题。
注意事项:压缩传输会导致长度对不上
如果服务器返回的响应头里有 Content-Encoding: gzip,Content-Length 通常是压缩后的体积,不是文件原始大小。 比如一个10MB的JSON日志,压缩后响应头可能显示2MB,这种情况下C语言想拿原始大小时,要么在请求头里加 Accept-Encoding: identity 强制服务器不压缩,要么干脆走SDK接口拿元数据。
国内主流云服务器场景下,C语言怎么实操
酷番云轻量应用服务器 + COS SDK
如果你的文件在酷番云COS上,C语言项目可以直接用酷番云官方提供的C SDK(基于libcurl封装),官方SDK里的 cos_get_object_meta 接口,底层原理也是发HEAD请求,但帮你处理了签名和鉴权逻辑,这里不适合手写HTTP签名,因为酷番云COS的请求头需要临时密钥,自己算容易踩时间戳和编码的坑。
简米云ECS + OSS 内网访问
在简米云ECS上跑C程序访问OSS时,优先使用内网Endpoint,比如你的ECS在华北2(北京),OSS的Bucket也在北京,请求地址应该写 https://your-bucket.oss-cn-beijing-internal.aliyuncs.com,走内网不仅速度快很多,还免流量费,C代码里除了URL换成内网地址,其他逻辑完全不变,如果你在百度搜“c语言怎么从云服务器读取文件大小”,搜到的大多数教程其实都是在讲ECS内网访问OSS的场景。
跨地域访问时,注意延迟和超时
假设服务器在成都地域,文件存储在新加坡地域的节点上,这种跨地域访问延迟较高,C代码里的libcurl超时时间建议设置15秒以上,否则高峰期容易握手失败。
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 15L); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60L);
读取大小之后,通常还要做两件事
拿到文件大小不是为了看一眼就完事,绝大多数项目实际应用场景是断点续传或下载进度条。
配合 Range 请求实现断点下载
知道文件总大小后,C语言结合HTTP的 Range 头就能分段拉取内容。
假设文件总大小 total_size = 1024000 字节,你要从第1字节开始,一次拉512KB,请求头这样设置:
char range_header[256]; snprintf(range_header, sizeof(range_header), "Range: bytes=%lld-%lld", start, end); curl_easy_setopt(curl, CURLOPT_RANGE, range_header);
这个技巧在做云服务器上的大文件下发工具时特别有用。
特殊情况:软链接和挂载盘
很多云服务器的数据盘是额外挂载的,路径 /home/ubuntu/data 可能本身是个软链接指向 /mnt/data。stat() 只会返回软链接指向的目标文件大小,这一点没问题,但如果你用 lstat(),返回的却是软链接本身的大小(通常只有几十字节)。
牢记行业共识:在云服务器脚本和C程序里读文件大小,永远用 stat() 而不是 lstat(),除非你明确就是想查链接本身的体积。
结尾建议
如果你问c语言怎么从云服务器读取文件大小,答案其实就是两句话:本地文件用 stat(),远程HTTP资源用 Content-Length 响应头,云服务器的存储本质只是换了访问路径,C语言的系统调用和网络库足够覆盖大部分场景,只要先确认文件归属地在哪,代码不需要写得太复杂。
常见问题快速解答
C语言读本地目录下所有文件的大小要怎么做?
用 opendir() + readdir() 循环遍历目录,对每个非目录项调用 stat() 累加大小,注意跳过 和 ,并拼接完整路径,如果目录里文件数量非常大,建议使用 nftw() 递归遍历,避免栈溢出。
为什么 fopen() 后再用 fseek() 和 ftell() 拿到的文件大小偶尔不准?
因为 fseek(f, 0, SEEK_END) 后调 ftell() 只能拿到当前打开实例的大小,如果文件恰好是持续写入的日志,ftell() 不会自动感知新写入内容,这种情况下建议用 stat() 一次性拿最新大小,不必重复打开文件流。
云服务器上文件大小显示为0,但网站能正常访问是什么原因?
如果文件是特殊字符设备或者 /proc 虚拟文件系统下的节点,stat() 返回的 st_size 为0是正常现象,这种情况要区分普通文件和流式文件,/proc/cpuinfo 这种虚拟文件,每次读取时内容实时生成,大小没有固定值。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/748302.html





