首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C語言獲取文件大小三種方法:fseek/ftell、stat 結構體、Windows API 對比

     編輯:關於C語言

獲取文件大小是系統編程高頻需求。本文對比三種主流方法:標準 C fseek/ftell、POSIX stat、Windows _stat/GetFileSizeEx,分析適用場景、類型陷阱、64 位大文件支持。

方法一:標準 C fseek/ftell (可移植、流式)

#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 文件溢出。
  • 文本模式下 Windows 換行符轉換導致位置不準,必須 "rb"。
  • 不支持管道/設備文件 (無法 seek)。

方法二:POSIX stat (元數據豐富、64 位就緒)

#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 路徑。

方法三:Windows API GetFileSizeEx (原生、大文件、句柄復用)

#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/ftellstatGetFileSizeEx
標準C89POSIXWin32 API
大文件 (>2GB)❌ long 溢出✅ off_t 64位✅ LARGE_INTEGER
元數據無豐富 (時間/權限/設備)需額外調用
管道/設備❌✅ (stat 可用)✅
性能需打開/關閉文件無需打開 (目錄項)需打開句柄
推薦場景教學/小文件/舊標準跨平台庫/工具/元數據需求Windows 專用/句柄復用

工程建議

  1. 庫開發統一用 stat 系:int64_t 返回類型,錯誤返回 -1 並設 errno。
  2. 大文件必須 64 位:編譯選項 -D_FILE_OFFSET_BITS=64 (GCC) 確保 off_t 為 64 位。
  3. 路徑編碼:Windows 廣義字符 wchar_t* + _wstat64/CreateFileW。
  4. 避免 TOCTOU:連續 stat + open 存在競態,關鍵路徑用 open + fstat 原子操作。

文件大小看似微末,實則觸及類型模型、平台抽象、大文件支持、競態條件等系統編程核心課題。選對 API,封裝好抽象層,是專業 C 開發者的基本功。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved