fread和内存映射读取二进制文件

结论先行:两种读取方式的耗时相差无几。
使用fread读取1.4G大小的二进制文件时,大概需要耗时7s。而再次读取同一个数据时,只需要不到1s的时间开销。因此,在此尝试使用内存映射进行读取,并与fread方法进行比较。
1. fread读取
使用fread读取二进制文件的步骤很简单,打开文件并读取就OK了。
其实现如下:

FILE* pFile = fopen("D:\\0TestData\\A.dat", "rb+");
if (pFile == NULL)
{
	printf("文件不存在\n");
	return ;
}
fseek(pFile, 56, 0);
fread(m_src, file_size, 1, pFile);
fclose(pFile);

2. 内存映射读取
使用内存映射的读取步骤如下:

1)调用CreateFile函数打开想要映射的文件,得到文件句柄hFile。
(2)调用CreateFileMapping函数,并传入文件句柄hFile,为该文件创建一个内存映射内核对象,得到内存映射文件的句柄hMap。
(3)调用MapViewOfFile函数映射整个文件或一部分到进程的虚拟地址空间。该函数返回文件映射到内存后的起始地址。使用指向这个地址的指针就可以读取文件的内容了。
(4)调用UnmapViewOfFile函数来解除文件映射。
(5)调用CloseHandle函数关闭文件对象,必须传入内存映射文件句柄hMap
(6)调用CloseHandle函数关闭文件对象,必须传入文件句柄hFile。

完整代码实现如下:

#include <windows.h>
#include <iostream>
#include<ctime>
#pragma warning(disable:4996)
void readFile1()
{
	size_t file_size = 1513881600;
	unsigned short* m_src = (unsigned short*)::malloc(file_size);
	//16位无符号型[0,65535]
	FILE* pFile = fopen("D:\\0TestData\\A.dat", "rb+");
	if (pFile == NULL)
	{
		printf("文件不存在\n");
		return ;
	}
	fseek(pFile, 56, 0);
	fread(m_src, file_size, 1, pFile);
	fclose(pFile);
	free(m_src);
}
int readFile2()
{
	HANDLE hFile = ::CreateFile("D:\\0TestData\\A.dat",
		GENERIC_READ,
		FILE_SHARE_READ,
		NULL,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL,
		NULL);
	if (hFile == INVALID_HANDLE_VALUE)
		return 1;

	do
	{

		size_t file_size = 1513881656;
		HANDLE map_file = ::CreateFileMapping(hFile,
			nullptr,
			PAGE_READONLY,
			0,
			0,
			nullptr);
		if (map_file == nullptr)
			break;

		do
		{
			LPVOID pMap = ::MapViewOfFile(map_file, FILE_MAP_READ, 0, 0, 0);
			if (pMap == nullptr)
				break;

			unsigned short* buf = (unsigned short*)::malloc(file_size);
			if (buf)
			{
				memcpy(buf, pMap, file_size);
				//std::cout << buf[2] << std::endl;
				::free(buf);
			}

			::UnmapViewOfFile(pMap);
		} while (0);

		::CloseHandle(map_file);
	} while (0);

	::CloseHandle(hFile);
}
int main()
{
	clock_t startTime, endTime;
	//fread读取
	startTime = clock();
	readFile1();
	endTime = clock();
	std::cout << "The total run time1 is:  " << (double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << std::endl;
	//内存映射读取
	startTime = clock();
	readFile2();
	endTime = clock();
	std::cout << "The total run time2 is:  " << (double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << std::endl;

	system("pause");
	return 0;
}

以上程序的运行结果如下:

The total run time1 is:  7.752s
The total run time2 is:  0.936s

看到这个结果开始我以为是内存映射读取速度快。为了更进一步验证,我更换了数据文件,单独运行,发现两种读取方式都相差无几。另外,就是读取同一文件时,读取一次后再次读取时间会大大缩短,这应该是数据被放到缓存中了。对此,在运行了几组数据后,查看了CPU的缓存一直在增加。
在这里插入图片描述

参考文献:
[1] 内存映射实现快速读取文件
[2] C++中使用内存映射技术

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值