在连续的非结构化文件流中搜索结构

时间:2014-11-19 03:43:55

标签: c++ windows stream unmanaged

我试图找出一种(希望很容易)读取大型非结构化文件的方法,而不会碰到缓冲区的边缘。这里有一个例子很有用。

想象一下,您正在尝试对16GB闪存驱动器进行一些数据恢复,并将驱动器转储保存到16GB文件中。您想要扫描图像,寻找感兴趣的特定项目。如果文件较小,您可以将整个内容读入内存缓冲区(假设为1MB)并对缓冲区进行简单扫描。但是,由于它太大而无法一次性读取,因此您需要以块的形式阅读它。问题是感兴趣的项目可能不完全对齐,以便落入单个1MB缓冲区内。换句话说,它可能最终跨越缓冲区的边缘,以便它在一次读取期间从缓冲区的末尾开始,并在下一个缓冲区结束时(或者甚至更远)。

在过去的某个时候,我通过使用两个缓冲区并将第二个缓冲区复制到第一个缓冲区以创建一种滑动窗口来解决这个问题,但我想这应该是一个常见的场景,有更好的,现有解决方案。我查看了内存映射文件,认为它们让你通过简单地增加数组索引/指针来读取文件,但由于地图视图大小的限制,我最终处于与以前完全相同的情况。我试着寻找一些使用带有偏移的MapViewOfFile的实际例子,但我所能找到的只是人为设想的例子而已经跳过了。

这种情况通常如何处理?

1 个答案:

答案 0 :(得分:0)

如果您在64位环境中运行,我只会使用内存映射文件。进程没有(合理的)内存限制。您可以读取文件,甚至可以跳转,操作系统会将内存与磁盘交换。

以下是一些基本信息:

http://msdn.microsoft.com/en-us/library/ms810613.aspx

这里有一个文件查看器的例子:

http://www.catch22.net/tuts/memory-techniques-part-1

此案例适用于x64中的2.8GB文件,但在win32中失败,因为每个进程无法分配超过2GB的文件。它非常快,因为它只接触pBuf数组中的第一个和最后一个字节。修改遍历缓冲区的方法并计算“零”的数量。 bytes按预期工作。你可以看到内存占用量上升,但内存只是虚拟分配。

#include "stdafx.h"
#include <string>
#include <Windows.h>

TCHAR  szName[] = TEXT( pathToFile );

int _tmain(int argc, _TCHAR* argv[])
{
   HANDLE hMapFile;
   char* pBuf;

   HANDLE file = CreateFile( szName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
   if ( file == NULL )
   {
         _tprintf(TEXT("Could not open file object (%d).\n"),
             GetLastError());
      return 1;
   }

   unsigned int length  = GetFileSize(file, 0);

   printf( "Length = %u\n", length );


   hMapFile = CreateFileMapping( file, 0, PAGE_READONLY, 0, 0, 0 );

   if (hMapFile == NULL)
   {
      _tprintf(TEXT("Could not create file mapping object (%d).\n"),  GetLastError());
      return 1;
   }

   pBuf = (char*) MapViewOfFile(hMapFile,  FILE_MAP_READ, 0,0, length);

   if (pBuf == NULL)
   {
      _tprintf(TEXT("Could not map view of file (%d).\n"), GetLastError());

       CloseHandle(hMapFile);

      return 1;
   }

   printf("First Byte: 0x%02x\n", pBuf[0] );
   printf("Last Byte: 0x%02x\n", pBuf[length-1] );
   UnmapViewOfFile(pBuf);

   CloseHandle(hMapFile);

   return 0;
}