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

Windows 文件映射實現超大數據高速存取:分段映射與跨邊界讀寫完整方案

     編輯:VC 教學

背景與痛點

專案需持續接收網路數據流並即時顯示影像,同時支援歷史數據任意位置回放。傳統 fwrite/fread 涉及用戶態/核心態多次複製,無法滿足 GB 級數據的高吞吐需求。Windows 文件映射 (CreateFileMapping + MapViewOfFile) 直接建立虛擬位址與磁碟檔案的對應,**省去複製開銷**,將檔案視為大型記憶體操作,效能提升數量級。

關鍵技術難點與解決方案

1. 大檔案不可一次完整映射

32 位進程位址空間僅 2GB,無法一次映射數 GB 檔案。解法:分塊映射(View),每次映射 64KB 整數倍區塊(系統配置粒度)。

2. 讀寫跨越 View 邊界

單次操作可能橫跨兩個相鄰 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;
}

效能實測與部署建議

  • 測試環境:順序寫入 10GB 數據,持續吞吐穩定在磁碟頻寬上限(~150MB/s SATA SSD)。
  • 隨機讀取 4KB 區塊,延遲 < 0.5ms(頁面錯誤由系統預讀優化)。
  • 跨平台提示:Linux 下可用 mmap 實現同樣語意,介面設計保持一致便於移植。

總結

文件映射 + 分段 View + 自動跨邊界切換,構建出高效、記憶體友善的大數據存取引擎。核心在於**將檔案視為可隨機存取的巨型陣列**,讓上層業務邏輯擺脫緩衝區管理的複雜度。

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