獲取文件大小是系統編程高頻需求。本文對比三種主流方法:標準 C fseek/ftell、POSIX stat、Windows _stat/GetFileSizeEx,分析適用場景、類型陷阱、64 位大文件支持。
#include <stdio.h>
#include <stdlib.h>
long file_size_fseek(const char *path) {
FILE *fp = fopen(path, "rb");
if (!fp) return -1;
if (fseek(fp, 0, SEEK_END) != 0) { fclose(fp); return -1; }
long size = ftell(fp);
fclose(fp);
return size; // -1 表示錯誤
}
缺陷:
long 通常 32 位,>2GB 文件溢出。"rb"。#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
#include <time.h>
#include <inttypes.h>
int64_t file_size_stat(const char *path) {
struct stat st;
if (stat(path, &st) != 0) return -1;
return (int64_t)st.st_size; // st_size 為 off_t,通常 64 位
}
// 額外獲得:時間、權限、設備、inode
void print_file_info(const char *path) {
struct stat st;
if (stat(path, &st) == 0) {
printf("Size: %jd\n", (intmax_t)st.st_size);
printf("Device: %d\n", st.st_dev);
printf("Inode: %lu\n", (unsigned long)st.st_ino);
printf("Mode: %o\n", st.st_mode);
printf("Modified: %s", ctime(&st.st_mtime));
}
}
Windows 兼容:MSVC 提供 _stat/_stat64、_wstat 支持 Unicode 路徑。
#include <windows.h>
#include <stdio.h>
#include <inttypes.h>
int64_t file_size_winapi(const char *path) {
HANDLE h = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE) return -1;
LARGE_INTEGER size;
BOOL ok = GetFileSizeEx(h, &size);
CloseHandle(h);
return ok ? (int64_t)size.QuadPart : -1;
}
// 寬字符版本 (支持 Unicode 路徑)
int64_t file_size_winapi_w(const wchar_t *path) {
HANDLE h = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE) return -1;
LARGE_INTEGER size;
BOOL ok = GetFileSizeEx(h, &size);
CloseHandle(h);
return ok ? (int64_t)size.QuadPart : -1;
}
#include <stdint.h>
#ifdef _WIN32
#define STAT_STRUCT _stat64
#define STAT_FUNC _stat64
#define OPEN_FLAGS _O_RDONLY | _O_BINARY
#else
#define STAT_STRUCT stat
#define STAT_FUNC stat
#endif
int64_t file_size(const char *path) {
STAT_STRUCT st;
if (STAT_FUNC(path, &st) != 0) return -1;
return (int64_t)st.st_size;
}
| 維度 | fseek/ftell | stat | GetFileSizeEx |
|---|---|---|---|
| 標準 | C89 | POSIX | Win32 API |
| 大文件 (>2GB) | ❌ long 溢出 | ✅ off_t 64位 | ✅ LARGE_INTEGER |
| 元數據 | 無 | 豐富 (時間/權限/設備) | 需額外調用 |
| 管道/設備 | ❌ | ✅ (stat 可用) | ✅ |
| 性能 | 需打開/關閉文件 | 無需打開 (目錄項) | 需打開句柄 |
| 推薦場景 | 教學/小文件/舊標準 | 跨平台庫/工具/元數據需求 | Windows 專用/句柄復用 |
int64_t 返回類型,錯誤返回 -1 並設 errno。-D_FILE_OFFSET_BITS=64 (GCC) 確保 off_t 為 64 位。wchar_t* + _wstat64/CreateFileW。stat + open 存在競態,關鍵路徑用 open + fstat 原子操作。文件大小看似微末,實則觸及類型模型、平台抽象、大文件支持、競態條件等系統編程核心課題。選對 API,封裝好抽象層,是專業 C 開發者的基本功。