如何使用c ++提高在Windows上读取数据的速度

时间:2014-05-27 11:07:21

标签: c++ windows performance file-io block

我正在使用CreateFile/ReadFile和4096字节的buffersize来读取卷快照中的数据块。 我面临的问题是ReadFile太慢,我能够在45秒内读取68439块,即267 Mb,我怎样才能提高速度?以下是我正在使用的代码的一部分,

block_handle = CreateFile(block_file,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if(block_handle != INVALID_HANDLE_VALUE)
{
    DWORD pos = -1;
    for(ULONG i = 0; i < 68439; i++)
    {
        sectorno = (i*8);
        distance = sectorno * sectorsize;
        phyoff.QuadPart = distance;     
        if(pos != phyoff.u.LowPart)
        {
             pos=SetFilePointer(block_handle, phyoff.u.LowPart,&phyoff.u.HighPart,FILE_BEGIN);
             if (phyoff.u.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
             {
                 printf("SetFilePointer Error: %d\n", GetLastError());
                 phyoff.QuadPart = -1;
                 return;
             }
        }
        ret = ReadFile(block_handle, data, 4096, &dwRead, 0);
        if(ret == FALSE)
        {
            printf("Error Read");
            return;
        }
        pos += 4096;
    }
}

我应该使用OVERLAPPED结构吗?或者可能的解决方案是什么? 注意:代码没有线程化。

等待积极回应。

3 个答案:

答案 0 :(得分:1)

我不太清楚你为什么要使用这些极低级别的系统功能。

我个人使用C风格的文件操作(使用fopen和fread)以及C ++风格的操作(使用fstream和read,参见this link)来读取原始二进制文件。从本地磁盘读取速度大约为100MB /秒。

在您的情况下,如果您不想使用标准的C或C ++文件操作,我的猜测是您的代码较慢的原因是由于您在每个块之后执行搜索。你真的需要为每个块调用SetFilePointer吗?如果块是顺序的,则不需要这样做。

另外,尝试不同的块大小,不要害怕超过1MB。

答案 1 :(得分:1)

您的问题是碎片数据读取。你不能通过摆弄ReadFile参数来解决这个问题。您需要对读取进行碎片整理。这里有三种方法:

  1. 对磁盘上的数据进行碎片整理

  2. 对读取进行碎片整理。也就是说,收集您需要的所有读数,但还没有读取任何内容。将读取排序为顺序。按顺序读取所有内容,尽可能跳过SetFilePointer(即顺序块)。这将大大加快总读数,但在第一次读取开始之前引入延迟。

  3. 内存映射数据。将所有数据复制到内存中并从内存中进行随机访问读取。这是否可行取决于总共有多少数据。

  4. 此外,您可能希望获得幻想,并尝试缓存。当您读取一个数据块时,可能是因为下一次读取不是连续的,但它很可能很接近。因此,当您读取一个块时,依次将大量附近数据块读入内存。在下次读取之前,检查新读取是否已经在内存中 - 从而保存了搜索和磁盘访问。测试,调试和调整这是很多工作,所以我不推荐它,除非这是一个关键任务优化。另请注意,您的操作系统和/或磁盘硬件可能已经在这些方面做了一些事情,所以要准备好看不出任何改进。

答案 2 :(得分:1)

  1. 如果可能的话,按顺序阅读(告诉CreateFile你打算用FILE_FLAG_SEQUENTIAL_SCAN顺序阅读。)
  2. 避免不必要的搜查。如果您按顺序阅读,则不需要任何搜索。
  3. 读取较大的块(类似于典型簇大小的整数倍)。我相信Windows自己的文件副本使用大约8 MB而不是4 KB的读取。考虑使用系统分配粒度的整数倍(可从GetSystemInfo获得)。
  4. 从对齐的偏移量中读取(您似乎正在这样做)。
  5. 读取页面对齐的缓冲区。请考虑使用VirtualAlloc分配缓冲区。
  6. 请注意,文件碎片会导致搜索费用昂贵。你无能为力。
  7. 请注意,卷压缩可能会使搜索特别昂贵,因为它可能必须从头开始解压缩文件以找到文件中间的起点。
  8. 请注意,卷加密可能会降低速度。你不能做多少但要注意。
  9. 请注意,每次触摸时,其他软件(如反恶意软件)可能会扫描整个文件。更少的操作将最大限度地减少这种打击。