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

MFC 處理大型資料檔案突破 64KB 限制:CFile::ReadHuge/WriteHuge 完整解析

     編輯:關於C語言

MFC CFile 與 CStdioFile 的 Read/Write 成員函式受限於 16 位元時代的 FAR 指標架構,單次傳輸上限為 65,535 位元組(64KB)。對於多媒體、科學計算、大型日誌等需頻繁讀寫 MB/GB 級資料的應用,分段迴圈不僅繁瑣易錯,更嚴重影響效能。本文揭示 MFC 未公開文件化的 ReadHuge/WriteHuge 兩大關鍵函式,並示範安全封裝與應用模式。

64KB 限制的根源

  • CFile::Read(void* lpBuf, UINT nCount) 參數 nCount 為 UINT(16 位元 VC 為 16-bit,32 位元 VC 為 32-bit 但內部仍用 FAR*)。
  • 內部呼叫 _lread/_lwrite 或 ReadFile/WriteFile 時,緩衝區指標若為 FAR*(近指標),無法跨段址址,導致 ASSERT(nCount <= 0xFFFF) 失敗。
  • HUGE 指標(__huge / __far16)可跨 64KB 邊界,但 MFC 公開介面未暴露。

隱藏寶藏:ReadHuge / WriteHuge

在 afx.h 中宣告(但未列入官方文件):

// CFile 成員函式
DWORD ReadHuge(void FAR* lpBuffer, DWORD dwCount);
void WriteHuge(const void FAR* lpBuffer, DWORD dwCount);
  • 參數 dwCount 為 DWORD(32 位元),理論支援 4GB 單次傳輸。
  • 內部使用 HUGE 指標運算,自動處理分段拷貝。
  • 回傳值:ReadHuge 實際讀取位元組數(0 表 EOF);WriteHuge 失敗拋 CFileException。

安全封裝類別:CBigFile

class CBigFile : public CFile
{
public:
    // 直接繼承,公開 Huge 版本
    using CFile::ReadHuge;
    using CFile::WriteHuge;

    // 便利覆寫:支援 CString/ByteArray 直接讀寫
    DWORD ReadStringBig(CString& rString, DWORD dwMaxChars = 0xFFFFFFFF) {
        // 內部分配 HUGE 緩衝區,呼叫 ReadHuge,轉換編碼
    }
    void WriteStringBig(const CString& rString) {
        // 寬字元轉多位元組,呼叫 WriteHuge
    }
    void WriteByteArray(const CByteArray& arr) {
        WriteHuge(arr.GetData(), (DWORD)arr.GetSize());
    }
};

實戰範例:複製 2GB 影片檔案

BOOL CopyLargeFile(LPCTSTR srcPath, LPCTSTR dstPath)
{
    CBigFile srcFile, dstFile;
    CFileException ex;

    if (!srcFile.Open(srcPath, CFile::modeRead | CFile::shareDenyWrite, &ex)) {
        ex.ReportError(); return FALSE;
    }
    if (!dstFile.Open(dstPath, CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive, &ex)) {
        srcFile.Close(); ex.ReportError(); return FALSE;
    }

    const DWORD BUF_SIZE = 1024 * 1024; // 1MB 緩衝區
    BYTE* pBuf = new BYTE[BUF_SIZE];
    DWORD dwRead;
    ULONGLONG total = 0;

    try {
        while ((dwRead = srcFile.ReadHuge(pBuf, BUF_SIZE)) > 0) {
            dstFile.WriteHuge(pBuf, dwRead);
            total += dwRead;
            // 可在此回報進度:total / srcFile.GetLength()
        }
    } catch (CFileException* e) {
        e->ReportError(); e->Delete(); delete[] pBuf; return FALSE;
    }

    delete[] pBuf;
    srcFile.Close(); dstFile.Close();
    return TRUE;
}

效能優化關鍵

技巧說明效能提升
大緩衝區(1-4MB)減少系統呼叫次數,發揮磁碟順序讀寫頻寬3-10x
非同步 I/O (FILE_FLAG_OVERLAPPED)配合 ReadFileEx/WriteFileEx 實現運算與 I/O 重疊雙核+ 顯著
記憶體映射檔 (CMapFile / CreateFileMapping)超大檔(>4GB)隨機存取、系統管理分頁隨機存取數量級
關閉壓縮/加密/防毒掃描針對特定目錄/副檔名排除避免額外 CPU/延遲

常見陷阱與除錯

  • 堆疊緩衝區過大:BYTE buf[1024*1024] 會爆堆疊,必須 new BYTE[size] 或 CByteArray。
  • 檔案指標位置:ReadHuge/WriteHuge 同樣遞移檔案指標,Seek 參數為 LONG(2GB 限制),超大檔請用 SeekHuge(同樣未文件化)或 SetFilePointerEx。
  • 共享模式衝突:大檔複製建議 shareDenyWrite(來源)+ shareExclusive(目的)。
  • 磁碟空間不足:寫入前以 GetDiskFreeSpaceEx 預檢。

替代方案對比

總結

CFile::ReadHuge/WriteHuge 是 MFC 開發者處理大型二進位檔案的「隱藏神器」,雖未正式文件化,但在 VC6 至 VS2022 所有版本中均穩定存在。配合大緩衝區、例外保護與進度回報,即可輕鬆突破 64KB 瓶頸。對於新專案或極致效能需求,建議直接使用 Win32 非同步 I/O 或記憶體映射檔,獲得更完整的控制與擴充性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
方案優點缺點適用場景
CFile::ReadHuge/WriteHugeMFC 原生、零依賴、程式碼改動最小未文件化、無 Unicode 路徑支援(VC6)、>4GB 需 SeekHuge既有 MFC 專案快速遷移
Win32 ReadFile/WriteFile + OVERLAPPED完整控制、支援非同步、>4GB 原生需自行管理緩衝區、錯誤處理繁瑣高效能、新專案
CStdioFile 分段迴圈文字模式自動換行轉換64KB 限制、二進位不適用純文字大檔
記憶體映射檔隨機存取極快、系統優化分頁佔用虛擬記憶體、32 位元程式受限 2GB資料庫、索引檔、科學資料