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

C語言取得檔案大小:_stat 與 fseek 兩種經典做法比較

     編輯:關於C語言

需求背景

在 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;        // 位元組數,有符號長整數
}
  • 優點:不需開啟檔案、支援目錄/裝置節點、可同時取得時間戳、權限、inode 等中繼資料。
  • 缺點:Windows 上 _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;
}
  • 優點:純標準 C,任何平台皆可編譯;支援管道、標準輸入等非可定位流 (會失敗回傳 -1)。
  • 缺點:需開啟檔案 (權限檢查、檔案鎖);ftell 回傳 long,32 位元平台同樣受限 2 GB;文字模式下 Windows 換行轉換導致位元組數不準。

64 位元檔案大小支援 (大於 2 GB)

平台函數/結構體型別範例
Linux/POSIXstat / struct statoff_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_tftello(fp)

跨平台封裝範例 (支援 > 4 GB)

#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一次滿足多項需求

常見坑點提醒

  1. 文字模式 fopen(path, "r"):Windows 將 \r\n 轉為 \n,導致 ftell 回傳邏輯位置而非實際位元組數 → 務必用 "rb"。
  2. 32 位元 long 溢位:超過 2,147,483,647 位元組的檔案會回傳負數 → 改用 64 位元 API。
  3. 目錄而非檔案:stat 對目錄也會成功,st_size 通常為區塊大小非內容總量 → 搭配 S_ISREG(st.st_mode) 判斷。
  4. 符號連結:stat 追蹤連結,lstat 不追蹤 → 視需求選擇。

結語

取得檔案大小看似簡單,實則涉及平台差異、64 位元支援、檔案系統語意。建議專案統一封裝 GetFileSize64(path) 並內部處理平台差異,上層業務邏輯僅依賴 int64_t 回傳值,避免 long 在 32/64 位元平台行為不一致導致隱蔽 Bug。

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