專案需持續接收網路數據流並即時顯示影像,同時支援歷史數據任意位置回放。傳統 fwrite/fread 涉及用戶態/核心態多次複製,無法滿足 GB 級數據的高吞吐需求。Windows 文件映射 (CreateFileMapping + MapViewOfFile) 直接建立虛擬位址與磁碟檔案的對應,**省去複製開銷**,將檔案視為大型記憶體操作,效能提升數量級。
32 位進程位址空間僅 2GB,無法一次映射數 GB 檔案。解法:分塊映射(View),每次映射 64KB 整數倍區塊(系統配置粒度)。
單次操作可能橫跨兩個相鄰 View。解法:檢測剩餘空間不足時,自動 UnmapViewOfFile 當前 View,映射下一個 View,繼續操作。
enstFileCache (Qt + WinAPI)class enstFileCache : public QObject {
// 映射參數
static const INT64 VIEW_SIZE = 1024 * 64 * 1024; // 64MB per view
HANDLE m_hFile, m_hMapping;
// 寫入狀態
INT64 m_writeMapOffset; LPVOID m_pWriteView; INT64 m_writeViewOffset;
// 讀取狀態
INT64 m_readMapOffset; LPVOID m_pReadView;
public:
bool CreateFileCache(const QString& path); // 建立/開啟檔案與映射物件
bool AppendData(const INT8* data, int len); // 追加寫入(自動跨 View)
bool ReadData(INT64 fileOffset, INT8* buf, int len); // 任意位置讀取(自動跨 View)
~enstFileCache(); // 解構時完整清理 View、Mapping、File Handle
};
bool enstFileCache::AppendData(INT8* pData, int len) {
int written = 0;
do {
// 1. 當前 View 剩餘空間
int canWrite = VIEW_SIZE - m_writeViewOffset;
if (m_pWriteView && canWrite <= 0) {
UnmapViewOfFile(m_pWriteView);
m_pWriteView = NULL;
m_writeMapOffset += VIEW_SIZE;
}
// 2. 需要映射新 View
if (!m_pWriteView) {
m_pWriteView = MapViewOfFile(m_hMapping, FILE_MAP_WRITE,
HIGH_DWORD(m_writeMapOffset), LOW_DWORD(m_writeMapOffset), VIEW_SIZE);
m_writeViewOffset = 0;
canWrite = VIEW_SIZE;
}
// 3. 複製數據
int toWrite = min(len - written, canWrite);
memcpy((BYTE*)m_pWriteView + m_writeViewOffset, pData + written, toWrite);
m_writeViewOffset += toWrite;
written += toWrite;
} while (written < len);
return true;
}
bool enstFileCache::ReadData(INT64 offset, INT8* buf, int len) {
int readed = 0;
do {
// 1. 計算當前 View 可讀範圍
int canRead = m_readMapOffset + VIEW_SIZE - offset - readed;
if (m_pReadView && (canRead <= 0 || canRead > VIEW_SIZE)) {
UnmapViewOfFile(m_pReadView);
m_pReadView = NULL;
}
// 2. 映射包含目標位移的 View
if (!m_pReadView) {
m_readMapOffset = (offset + readed) / VIEW_SIZE * VIEW_SIZE; // 對齊 64KB
m_pReadView = MapViewOfFile(m_hMapping, FILE_MAP_READ,
HIGH_DWORD(m_readMapOffset), LOW_DWORD(m_readMapOffset), VIEW_SIZE);
canRead = m_readMapOffset + VIEW_SIZE - offset - readed;
}
// 3. 複製數據
int toRead = min(len - readed, canRead);
memcpy(buf + readed,
(BYTE*)m_pReadView + offset - m_readMapOffset + readed,
toRead);
readed += toRead;
} while (readed < len);
return true;
}
mmap 實現同樣語意,介面設計保持一致便於移植。文件映射 + 分段 View + 自動跨邊界切換,構建出高效、記憶體友善的大數據存取引擎。核心在於**將檔案視為可隨機存取的巨型陣列**,讓上層業務邏輯擺脫緩衝區管理的複雜度。