傳統 ftell 返回 long 型別,在 32 位系統上限制為 2GB,無法應對現代大文件(如 10GB+ 遊戲安裝包)。本文遞進式介紹從 32 位舊寫法到跨平台 64 位解決方案的完整演進過程。
long file_getsize(const char *path) {
FILE *fp = fopen(path, "rb");
if (!fp) return 0;
fseek(fp, 0, SEEK_END);
long size = ftell(fp);
fclose(fp);
return size;
}
缺陷:long 32 位為 4 位元組,最大值 2,147,483,647 (≈2GB)。大文件會溢出返回負值或錯誤值。
使用 _stat64 結構體,st_size 為 64 位整數:
#include <sys/types.h>
#include <sys/stat.h>
#include <inttypes.h> // PRId64
int64_t file_getsize(const char *path) {
struct _stat64 info = {0};
if (!path || !*path) return 0;
if (_stat64(path, &info) != 0) return 0;
return info.st_size;
}
測試 4.3GB 文件正確返回 4638924800。
Linux stat 在 64 位系統自動為 stat64,st_size 為 off_t (通常 8 位元組):
#include <sys/stat.h>
#include <inttypes.h>
int64_t file_getsize(const char *path) {
struct stat info = {0};
if (!path || !*path) return 0;
if (stat(path, &info) != 0) return 0;
return info.st_size;
}
編譯:gcc -Wall -ggdb2 -o main_linux.out main_linux.c
利用編譯器預定義巨集區分平台:
#if defined(_MSC_VER) || defined(_WIN32)
#define STAT_STRUCT _stat64
#define STAT_FUNC _stat64
#else
#define STAT_STRUCT stat
#define STAT_FUNC stat
#endif
int64_t file_getsize(const char *path) {
STAT_STRUCT info = {0};
if (!path || !*path) return 0;
if (STAT_FUNC(path, &info) != 0) return 0;
return info.st_size;
}
| 平台 | 結構體 | 大小欄位 | 型別 | 位數 |
|---|---|---|---|---|
| Windows 32/64 | _stat64 | st_size | __int64 / long long | 64 |
| Linux 64 位 | stat (==stat64) | st_size | off_t (long) | 64 |
| Linux 32 位 | stat64 | st_size | off64_t | 64 |
| POSIX 標準 | stat | st_size | off_t | 實現定義 |
fseek/ftell:需移動檔案指標,系統調用開銷大stat 族:直接讀取 inode 元數據,無需開啟文件,**效能高階數量級**#include <stdio.h>
#include <inttypes.h>
int64_t file_getsize(const char *path);
int main(int argc, char *argv[]) {
for (int i = 1; i < argc; i++) {
printf("%s => %" PRId64 "\n", argv[i], file_getsize(argv[i]));
}
return 0;
}
ftell:無法支援 >2GB 文件stat 族:高效、無需開啟文件、原生 64 位int64_t/PRId64:跨平台型別與格式化_MSC_VER、_WIN32 區分 Windows「C 語言細節繁多,但對於極致效能與資源控制,無可替代。選擇適合的工具,而非尋找完美的語言。」

有夢想的人令人羨慕,也令人惋惜。愛所愛,開心就好。