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

VC++大文件分割工具:基於內存映射的高性能實現(支援3GB+)

     編輯:關於C語言

專案背景

需分割巨大SQL文件,傳統讀寫方式過慢。採用內存映射文件技術,將文件直接映射至進程地址空間,避免用戶態/內核態重複拷貝,速度大幅提升。當前版本支援最大3GB文件,規劃64位版支援16EB。

工具運行截圖1 工具運行截圖2

使用說明

用法: SplitFile -f <源文件> -s <分塊大小KB> [-h]
選項:
  -f  指定待分割文件路徑
  -s  指定每塊大小(單位:KB)
  -h  顯示幫助信息
示例: SplitFile -f data.sql -s 1024

核心代碼解析

關鍵數據結構

typedef struct FILEINFO {
    LPSTR lpFileName;
    DWORD dwFileLowSize;
    DWORD dwFileHighSize;
    DWORD dwFileSize;
    DWORD dwPartNum;
} FILEINFO;

主流程:映射→分塊→寫入

int main(int argc, char *argv[]) {
    HANDLE hInFile = INVALID_HANDLE_VALUE, hInMap;
    FILEINFO fi = {0};
    BOOL bHelp = FALSE;
    DWORD dwPartSize = 0;

    // 參數解析
    for (int i = 0; i < argc; i++) {
        if (argc == 1) { bHelp = TRUE; continue; }
        LPSTR lpChkCmd = argv[i], lpValue = argv[i+1];
        if (lstrcmp(lpChkCmd, "-f") == 0) fi.lpFileName = lpValue;
        else if (lstrcmp(lpChkCmd, "-s") == 0) dwPartSize = atol(lpValue) * 1024;
        else if (lstrcmp(lpChkCmd, "-h") == 0) bHelp = TRUE;
    }
    if (bHelp) { PrintUsage(argv[0]); exit(1); }

    // 打開源文件並創建映射
    hInFile = CreateFile(fi.lpFileName, GENERIC_READ|GENERIC_WRITE,
                         FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hInFile == INVALID_HANDLE_VALUE) { PrintError("打開文件失敗"); return 0; }

    fi.dwFileLowSize = GetFileSize(hInFile, &fi.dwFileHighSize);
    fi.dwFileSize = fi.dwFileLowSize; // 當前僅支援低32位

    hInMap = CreateFileMapping(hInFile, NULL, PAGE_READWRITE, 0, 0, NULL);
    if (!hInMap) { PrintError("創建源文件映射失敗"); CloseHandle(hInFile); return 0; }

    // 計算分塊數
    fi.dwPartNum = fi.dwFileSize / dwPartSize;
    if (fi.dwFileSize % dwPartSize) fi.dwPartNum++;
    printf("文件大小:%u KB  分塊數:%u\n", fi.dwFileSize/1024, fi.dwPartNum);
    system("pause");

    DWORD dwBegin = GetTickCount(), dwCurAddr = 0;
    for (int index = 0; index < fi.dwPartNum; index++) {
        DWORD dwCurSize = min(dwPartSize, fi.dwFileSize - dwCurAddr);

        // 映射源文件當前視圖
        LPVOID lpInMapContext = MapViewOfFile(hInMap, FILE_MAP_READ|FILE_MAP_WRITE,
                                              0, dwCurAddr, dwCurSize);
        if (!lpInMapContext) { PrintError("創建源文件視圖失敗"); Cleanup(); return 0; }

        // 創建目標文件及映射
        char cIndex[4]; itoa(index+1, cIndex, 10);
        HANDLE hOutFile = CreateFile(cIndex, GENERIC_ALL, FILE_SHARE_READ|FILE_SHARE_WRITE,
                                     NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
        HANDLE hOutMap = CreateFileMapping(hOutFile, NULL, PAGE_READWRITE, 0, dwCurSize, NULL);
        LPVOID lpOutMapContext = MapViewOfFile(hOutMap, FILE_MAP_WRITE, 0, 0, 0);

        // 內存級拷貝(極速)
        CopyMemory(lpOutMapContext, lpInMapContext, dwCurSize);
        printf("[MSG]分塊%d完成.\n", index+1);

        // 釋放當前塊資源
        UnmapViewOfFile(lpInMapContext);
        UnmapViewOfFile(lpOutMapContext);
        CloseHandle(hOutMap); CloseHandle(hOutFile);
        dwCurAddr += dwCurSize;
    }

    CloseHandle(hInMap); CloseHandle(hInFile);
    printf("用時:%u毫秒\n", GetTickCount() - dwBegin);
    return 1;
}

技術優勢總結

  • 零拷貝核心:`MapViewOfFile` + `CopyMemory` 直接在用戶態完成數據傳輸,省去 `ReadFile`/`WriteFile` 的內核緩衝區拷貝。
  • 大文件友好:分塊映射視圖,避免一次性佔用巨大虛擬地址空間。
  • 擴展性強:64位版只需調整 `CreateFileMapping` 高位參數與 `MapViewOfFile` 偏移類型,即可突破3GB限制。

代碼為快速Demo風格,生產環境建議加強異常處理、進度顯示、校驗碼驗證等功能。


本文出自「About:Blank H4cking」博客,轉載請保留出處。

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