牛骨文教育服务平台(让学习变的简单)
博文笔记

c++ 利用内存映射读取大文件

创建时间:2013-09-05 投稿人: 浏览次数:4343

由于用到的txt存放的数据有几十万行,用getline来读取文件非常慢,搜索了一下可以来优化读取文件的方法。

据说用内存映射读取文件速度快,试了一下,但是发现要分行处理数据时,速度还是挺慢的。

有关内存映射的介绍,参考别人博客。

http://blog.csdn.net/wcyoot/article/details/7363393

/////////////////////////////////////////////////////////////////////////////
///创建镜像文件来读取文件,提高速度
///////////////////////////////////////////////////////////////////////////
void useMapFileReadText(){

		HANDLE hFile = NULL, hFileMap = NULL;
		char * lpbMapAddress = NULL;
		int nFileSize = 0, nLeftSize = 0;
		if(hFile == NULL)
		{
			hFile = CreateFile("data.txt", GENERIC_READ, 0, NULL,
				OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
			if(hFile == INVALID_HANDLE_VALUE)
			{
				printf("打开文件失败");
			}
		}
		if(hFileMap == NULL)
		{
			hFileMap=CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
			if(hFileMap==NULL)
			{
				OutputDebugString("文件镜像句柄创建失败!");
				CloseHandle(hFile);
			}
		}
		if(lpbMapAddress == NULL)
		{
			lpbMapAddress = (char *)MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
			if(lpbMapAddress == NULL)
			{
				OutputDebugString("内存映射文件失败!");
				CloseHandle(hFileMap);
				CloseHandle(hFile);
			}		
		}

		const char* buf = lpbMapAddress;
		const char* start = lpbMapAddress;
		int len;
		while(start != NULL){
			start = _get_line(buf, &len);
			string str(buf,len);
			//////////////do something with str
			buf = start;
		}
		//释放
		UnmapViewOfFile(hFile); 
		CloseHandle(hFileMap); 
}



其中的,_get_line 函数

" " 在windows中为0x0d 0x0a 占两个字符,在linux系统中为0x0a占一个字符。

//buf:从当前地址开始搜索。
//len: 存放该行的字符串长度,不包含回车换行符。
//返回值:下一次搜索开始的地址.如果到达文件尾,则返回NULL
const char* _get_line(const char* buf, int* len)
{
	const char* tmp = buf;
	while(*tmp && (*tmp != 0x0d && *tmp != 0x0a && *tmp != "
")) ++tmp;
	//while(*tmp && (*tmp != 0x0d || *tmp != 0x0a )) ++tmp;
	*len = tmp - buf; //

	if (*tmp == 0) return NULL;

	// skip New-Line char
	if (*tmp == 0x0d){ // Windows style New-Line 0x0d 0x0a
		tmp += 2;
		//assert(*tmp == 0x0a);
	}//else Unix style New-Line 0x0a
	else{
       ++tmp;
	}

	return tmp;
}


用十三万多行来测试,这样按行来处理时,不如getiline速度快。

内存映射的优势还是在于大文件。

fstream.open() 时,由于文件太大,IO一次读不了所有的数据,需要多次IO操作。

而内存映射,并不是将文件加载到内存。内存映射首先申请一段地址空间,并映射到物理存储器,而这里的物理存储器就是文件所在的磁盘,类似虚拟内存(pagefile);
当有需要时,程序不需要先把它加到内存,而是直接从磁盘读取。这样就减少了IO操作。


 内存映射的一个优势还在于多个进程之间共享数据。 

声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。