MFC CFile 與 CStdioFile 的 Read/Write 成員函式受限於 16 位元時代的 FAR 指標架構,單次傳輸上限為 65,535 位元組(64KB)。對於多媒體、科學計算、大型日誌等需頻繁讀寫 MB/GB 級資料的應用,分段迴圈不僅繁瑣易錯,更嚴重影響效能。本文揭示 MFC 未公開文件化的 ReadHuge/WriteHuge 兩大關鍵函式,並示範安全封裝與應用模式。
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 公開介面未暴露。在 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。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());
}
};
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 原生、零依賴、程式碼改動最小 | 未文件化、無 Unicode 路徑支援(VC6)、>4GB 需 SeekHuge | 既有 MFC 專案快速遷移 |
Win32 ReadFile/WriteFile + OVERLAPPED | 完整控制、支援非同步、>4GB 原生 | 需自行管理緩衝區、錯誤處理繁瑣 | 高效能、新專案 |
CStdioFile 分段迴圈 | 文字模式自動換行轉換 | 64KB 限制、二進位不適用 | 純文字大檔 |
| 記憶體映射檔 | 隨機存取極快、系統優化分頁 | 佔用虛擬記憶體、32 位元程式受限 2GB | 資料庫、索引檔、科學資料 |