文件重叠操作

示例中分别使用了重叠结构与非重叠结构操作文件,你可以根据实际中的需求自己取舍。示例中有对API的简单注释,代码方便大家学习,共同进步。
如有不足,留言反馈

#include <windows.h>

int MAX_READ = (1024 * 1024);

/************************一般的读写文件操作************************/
void NomalReadWrite(TCHAR* pReadFile, TCHAR* pWriteFile)
{
    // 读句柄
    HANDLE hReadFile = CreateFile(
        pReadFile,                          // 指向文件名的指针 
        GENERIC_READ,                       // 访问模式(写 / 读) GENERIC_ALL(读写)
        FILE_SHARE_READ | FILE_SHARE_WRITE, // 共享模式 (读,写)
        0,                                  // 指向安全属性的指针 
        OPEN_EXISTING,                      // 如何创建 
        FILE_ATTRIBUTE_NORMAL,              // 文件属性 
        0);                                 // 用于复制文件句柄 
    // 写句柄
    HANDLE hWriteFile = CreateFile(pWriteFile, 
        GENERIC_WRITE,
        FILE_SHARE_WRITE,
        0,
        OPEN_ALWAYS,                        // Opens a file, always.
        FILE_ATTRIBUTE_NORMAL,
        0);
    if (hReadFile == INVALID_HANDLE_VALUE || hWriteFile == INVALID_HANDLE_VALUE)
        return;

    BYTE * buf = new BYTE[MAX_READ];
    DWORD nBytesRead = -1;
    DWORD nBytesWrite = 0;

    while (nBytesRead != 0)// 文件读取完毕时,nBytesRead为0
    {
        if (!ReadFile(hReadFile, buf, MAX_READ, &nBytesRead, NULL))
            break;
        if (!WriteFile(hWriteFile, buf, nBytesRead, &nBytesWrite, NULL))
            break;
    }

    CloseHandle(hReadFile);
    CloseHandle(hWriteFile);
    delete[] buf;
}

struct stBufInfo
{
    BYTE** arrBuf;          //异步读取的数据
    DWORD* arrBytesRead;    //读取的字节数
};

/********************重叠模式的读写文件操作(多次IO操作读取)*********************/
void MoreOverlapdReadWrite(TCHAR* pReadFile, TCHAR* pWriteFile)
{
    HANDLE hReadFile = CreateFile(pReadFile,        
        GENERIC_READ,       // 读文件模式                        
        FILE_SHARE_READ | FILE_SHARE_WRITE, 
        0,                                  
        OPEN_EXISTING,                      
        FILE_FLAG_OVERLAPPED,// 使用重叠IO模式读取文件
        0);                             
    if (hReadFile == INVALID_HANDLE_VALUE)
        return;
    DWORD dwSize = GetFileSize(hReadFile, NULL);
    if (dwSize > MAX_READ * 63) //  WaitForMultipleObjects一次最多只能等待64个事件对象,所以我们必须保证n的大小<=64
        MAX_READ = dwSize / 63;
    const int n = dwSize / MAX_READ + 1;
    stBufInfo bufInfo = { 0 };
    bufInfo.arrBuf = new BYTE*[n];
    bufInfo.arrBytesRead = new DWORD[n];
    LPOVERLAPPED ovlp = new OVERLAPPED[n];
    HANDLE* arrEvt = new HANDLE[n];
    BOOL bRet;

    for (int i = 0; i < n; i++)
    {
        bufInfo.arrBuf[i] = new BYTE[MAX_READ];
        ZeroMemory(&ovlp[i], sizeof(OVERLAPPED));
        ovlp[i].Offset = i * MAX_READ;
        ovlp[i].OffsetHigh = 0;
        arrEvt[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
        ovlp[i].hEvent = arrEvt[i];

        // 记录每次读取的字节数,在ReadFile里面,此时是重叠结构,返回读取到的字节不准确(多数返回0),所以在这里记录
        // 或者使用ReadFileEx+完成例程,在里面获取读取到的字节数
        if (i == n - 1)
        {
            bufInfo.arrBytesRead[i] = dwSize % MAX_READ;
            ZeroMemory(bufInfo.arrBuf[i], MAX_READ);
        }
        else
            bufInfo.arrBytesRead[i] = MAX_READ;

        bRet = ReadFileEx(hReadFile, bufInfo.arrBuf[i], MAX_READ, &ovlp[i], NULL);//最后一个参数就是指向一个完成例程函数的指针
        //bRet = ReadFile(hReadFile, bufInfo.arrBuf[i], MAX_READ, NULL, &ovlp[i]);
        if (!bRet)
        {       
            if (GetLastError() != ERROR_IO_PENDING)//ERROR_IO_PENDINGIO等待 表示 这次操作没有立即完成(不算文件读取错误)
            {
                Sleep(10);
                CloseHandle(arrEvt[i]);
                i--;
                continue;
            }
        }
    }

    // 最后两个参数 TRUE INFINITE 无限等待所有重叠操作的事件有信号到来,此时文件读取完成
    WaitForMultipleObjects(n, arrEvt, TRUE, INFINITE);
    // 到此,所有的文件读取已经完成
    for (int i = 0; i < n; i++)// 关闭所有事件对象句柄
        CloseHandle(arrEvt[i]);

    HANDLE hWriteFile = CreateFile(pWriteFile,
        GENERIC_WRITE,      // 写文件模式
        FILE_SHARE_WRITE,
        0,
        OPEN_ALWAYS,
        FILE_FLAG_OVERLAPPED,// 使用重叠IO模式写文件
        0);
    if (hWriteFile == INVALID_HANDLE_VALUE)
        return;

    DWORD nBytesWrite;
    for (int i = 0; i < n; i++)
    {
        ZeroMemory(&ovlp[i], sizeof(OVERLAPPED));
        ovlp[i].Offset = i * MAX_READ;
        ovlp[i].OffsetHigh = 0;
        arrEvt[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
        ovlp[i].hEvent = arrEvt[i];

        bRet = WriteFileEx(hWriteFile, bufInfo.arrBuf[i], bufInfo.arrBytesRead[i], &ovlp[i], NULL);
        //bRet = WriteFile(hWriteFile, bufInfo.arrBuf[i], bufInfo.arrBytesRead[i], &nBytesWrite, &ovlp[i]);
        if (!bRet)
        {
            if (GetLastError() != ERROR_IO_PENDING)
            {
                Sleep(10);
                CloseHandle(arrEvt[i]);
                i--;
                continue;
            }
        }
    }

    WaitForMultipleObjects(n, arrEvt, TRUE, INFINITE);
    // 到此,所有文件写入完毕
    CloseHandle(hReadFile);
    CloseHandle(hWriteFile);
    for (int i = 0; i < n; i++)
    {
        delete[] bufInfo.arrBuf[i];
        CloseHandle(arrEvt[i]);
    }
}

int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd)
{
    NomalReadWrite(L"H:\\setup1.exe", L"h:\\test\\setup.exe");
    //MoreOverlapdReadWrite(L"H:\\setup1.exe", L"h:\\test\\setup.exe");

    return 0;
}

/***********重叠结构****************************
typedef struct _OVERLAPPED {
    ULONG_PTR Internal;
    ULONG_PTR InternalHigh;
    union {
        struct {
            DWORD Offset;
            DWORD OffsetHigh;
        } DUMMYSTRUCTNAME;
        PVOID Pointer;
    } DUMMYUNIONNAME;

    HANDLE  hEvent;
} OVERLAPPED, *LPOVERLAPPED;
******************************************/
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值