在 C 語言中取得檔案大小是常見需求:上傳前檢查、分配緩衝區、顯示進度列、斷點續傳計算位移。標準 C 庫 (C89) 未提供直接函數,需結合平台 API 或檔案操作技巧實現。
_stat / stat (POSIX / Windows 通用)#include <sys/stat.h> // Linux/macOS:
#include <stdio.h>
#include <stdlib.h>
long GetFileSize_Stat(const char *path)
{
struct stat st; // Windows 用 _stat, 結構體為 _stat
if (stat(path, &st) != 0) { // Windows: _stat(path, &st)
perror("stat failed");
return -1;
}
return (long)st.st_size; // 位元組數,有符號長整數
}
_stat 回傳 32 位元 st_size,超過 2 GB 檔案會溢位;需用 _stati64 / struct _stati64 取得 64 位元大小。fseek + ftell (標準 C 庫,極高可移植性)#include <stdio.h>
long GetFileSize_FSeek(FILE *fp)
{
long cur = ftell(fp); // 記住當前位置
if (cur == -1L) return -1;
if (fseek(fp, 0, SEEK_END) != 0) return -1;
long size = ftell(fp);
fseek(fp, cur, SEEK_SET); // 還原位置
return size;
}
// 便利包裝:直接傳路徑
long GetFileSize_Path(const char *path)
{
FILE *fp = fopen(path, "rb"); // 二進位模式避免換行轉換影響 ftell
if (!fp) return -1;
long sz = GetFileSize_FSeek(fp);
fclose(fp);
return sz;
}
ftell 回傳 long,32 位元平台同樣受限 2 GB;文字模式下 Windows 換行轉換導致位元組數不準。| 平台 | 函數/結構體 | 型別 | 範例 |
|---|---|---|---|
| Linux/POSIX | stat / struct stat | off_t (通常 64 位) | st.st_size |
| Windows (MSVC) | _stati64 / struct _stati64 | _off64_t (long long) | st.st_size |
| Windows (MinGW) | stat / struct stat (定義 _FILE_OFFSET_BITS=64) | off_t (long long) | st.st_size |
| 標準 C (C11) | fseek/ftello (POSIX.1-2008) | off_t | ftello(fp) |
#ifdef _WIN32
#include <io.h>
#include <sys/stat.h>
#define STAT_STRUCT _stati64
#define STAT_FUNC _stati64
typedef _off64_t fsize_t;
#else
#include <sys/stat.h>
#define STAT_STRUCT stat
#define STAT_FUNC stat
typedef off_t fsize_t;
#endif
fsize_t GetFileSize64(const char *path)
{
STAT_STRUCT st;
if (STAT_FUNC(path, &st) != 0) return -1;
return st.st_size;
}
| 場景 | 推薦方法 | 理由 |
|---|---|---|
| 單純取得大小、不需讀內容 | stat/_stat | 系統呼叫一次,無檔案開啟開銷 |
| 緊接著要讀取檔案內容 | fopen + fseek/ftell | 已持有 FILE*,避免雙重系統呼叫 |
| 嵌入式/無標準庫環境 | 平台原生 API (如 FATFS f_stat) | 不依賴 libc |
| 需同時取得修改時間、權限 | stat | 一次滿足多項需求 |
fopen(path, "r"):Windows 將 \r\n 轉為 \n,導致 ftell 回傳邏輯位置而非實際位元組數 → 務必用 "rb"。long 溢位:超過 2,147,483,647 位元組的檔案會回傳負數 → 改用 64 位元 API。stat 對目錄也會成功,st_size 通常為區塊大小非內容總量 → 搭配 S_ISREG(st.st_mode) 判斷。stat 追蹤連結,lstat 不追蹤 → 視需求選擇。取得檔案大小看似簡單,實則涉及平台差異、64 位元支援、檔案系統語意。建議專案統一封裝 GetFileSize64(path) 並內部處理平台差異,上層業務邏輯僅依賴 int64_t 回傳值,避免 long 在 32/64 位元平台行為不一致導致隱蔽 Bug。