Windows Practice_文件_内存映射(一)
来源:互联网 发布:我怎么投诉淘宝店铺 编辑:程序博客网 时间:2024/06/08 08:47
大文件数据操作
我们以全国开放数据(数据纯属伪造)为例,它的文件格式是csv,也是经常使用的一种文件存储格式,它是以逗号和换行来进行区分数据段和行来进行数据的区分。
今天我们把一个文件中的2000000条数据进行处理。
文件操作的几种方式
#include <stdio.h>#include <Windows.h>#include <clocale>const UINT MAXLINESIZE = 1024;wchar_t *Utf8ToUnicode(BYTE *strUtfData){ int iLen = MultiByteToWideChar(CP_UTF8, 0, reinterpret_cast<char *>(strUtfData), -1, nullptr, 0); wchar_t *strRet = new wchar_t[iLen]; MultiByteToWideChar(CP_UTF8, 0, reinterpret_cast<char *>(strUtfData), -1, strRet, iLen); return strRet;}BOOL ReadLine(const HANDLE hFile, BYTE *strBuf, UINT uMax = MAXLINESIZE){ BOOL bRet = FALSE; BYTE byteTemp; UINT uIndex = 0; DWORD dwReadLen; while (ReadFile(hFile, &byteTemp, sizeof(BYTE), &dwReadLen, nullptr)) { if (dwReadLen != sizeof(BYTE)) { break; } if (byteTemp == '\n') { bRet = TRUE; break; } else { if (uIndex < uMax) { strBuf[uIndex++] = byteTemp; } } } return bRet;}void ReadFromFile(){ setlocale(LC_ALL, "chs"); wchar_t *wstrFilePath = L"1.csv"; HANDLE hFile = CreateFile(wstrFilePath, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); if (INVALID_HANDLE_VALUE != hFile) { DWORD dwPrevTime = GetTickCount(); DWORD dwCount = 0; BYTE byteArray[MAXLINESIZE] = { 0 }; //wchar_t *wstrSearchData = L"1990"; while (ReadLine(hFile, byteArray)) { wchar_t *wstrTemp = Utf8ToUnicode(byteArray); if (wcsstr(wstrTemp, L"1990") != nullptr) { ++dwCount; } memset(byteArray, 0, MAXLINESIZE); } DWORD dwCurTime = GetTickCount(); DWORD dwTimeElaped = dwCurTime - dwPrevTime; wprintf(L"共找到:%d 条符合条件的记录, 用时:%d毫秒。\r\n", dwCount, dwTimeElaped); CloseHandle(hFile); } else { // 错误处理 wchar_t wstrMessage[MAXBYTE] = { 0 }; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(), 0, wstrMessage, MAXBYTE, nullptr); wprintf(L"打开文件失败,错误原因是:%s\r\n", wstrMessage); }}void ReadFromFileMap(){ setlocale(LC_ALL, "chs"); wchar_t *wstrFilePath = L"1.csv"; DWORD dwPrevTime = GetTickCount(); DWORD dwCount = 0; HANDLE hFile = CreateFile(wstrFilePath, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); if (INVALID_HANDLE_VALUE != hFile) { HANDLE hFileMap = CreateFileMapping(hFile, nullptr, PAGE_READONLY, 0, 0, nullptr); if (hFileMap != nullptr) { char *pFileMapAddr = (char *)MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0); MEMORY_BASIC_INFORMATION memBuffer; VirtualQuery(pFileMapAddr, &memBuffer, sizeof(MEMORY_BASIC_INFORMATION)); BYTE byteTemp[MAXLINESIZE] = { 0 }; UINT uIndex = 0; for (UINT i = 0; i < memBuffer.RegionSize; ++i) { if (pFileMapAddr[i] != '\n') { byteTemp[uIndex++] = pFileMapAddr[i]; if (pFileMapAddr[i] == '\0') { UnmapViewOfFile(pFileMapAddr); break; } } else { wchar_t *pTemp = Utf8ToUnicode(byteTemp); if (wcsstr(pTemp, L"1990") != nullptr) { ++dwCount; //wprintf(L"%s", pTemp); } uIndex = 0; memset(byteTemp, 0, MAXLINESIZE); delete[] pTemp; } } UnmapViewOfFile(pFileMapAddr); CloseHandle(hFileMap); } else { wchar_t wstrMessage[MAXBYTE] = { 0 }; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(), 0, wstrMessage, MAXBYTE, nullptr); wprintf(L"文件映射失败,错误原因是:%s\r\n", wstrMessage); } CloseHandle(hFile); } else { // 错误处理 wchar_t wstrMessage[MAXBYTE] = { 0 }; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(), 0, wstrMessage, MAXBYTE, nullptr); wprintf(L"打开文件失败,错误原因是:%s\r\n", wstrMessage); } DWORD dwCurTime = GetTickCount(); DWORD dwTimeElaped = dwCurTime - dwPrevTime; wprintf(L"共找到:%d 条符合条件的记录, 用时:%d毫秒。\r\n", dwCount, dwTimeElaped);}void ReadFromMemory(){ setlocale(LC_ALL, "chs"); wchar_t *wstrFilePath = L"1.csv"; DWORD dwPrevTime = GetTickCount(); DWORD dwCount = 0; HANDLE hFile = CreateFile(wstrFilePath, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); if (INVALID_HANDLE_VALUE != hFile) { // 获取文件大小 LARGE_INTEGER largeInteger; if (GetFileSizeEx(hFile, &largeInteger)) { char *pFilldata = new char[largeInteger.QuadPart]; if (ReadFile(hFile, pFilldata, largeInteger.QuadPart, nullptr, nullptr)) { BYTE byteTemp[MAXLINESIZE] = { 0 }; UINT uIndex = 0; for (UINT i = 0; i < largeInteger.QuadPart; ++i) { if (pFilldata[i] != '\n') { byteTemp[uIndex++] = pFilldata[i]; if (pFilldata[i] == '\0') { break; } } else { wchar_t *pTemp = Utf8ToUnicode(byteTemp); if (wcsstr(pTemp, L"1990") != nullptr) { ++dwCount; } uIndex = 0; memset(byteTemp, 0, MAXLINESIZE); delete[] pTemp; } } delete[] pFilldata; } else { wchar_t wstrMessage[MAXBYTE] = { 0 }; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(), 0, wstrMessage, MAXBYTE, nullptr); wprintf(L"读取文件内容失败,错误原因是:%s\r\n", wstrMessage); } } else { wchar_t wstrMessage[MAXBYTE] = { 0 }; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(), 0, wstrMessage, MAXBYTE, nullptr); wprintf(L"获取文件大小失败,错误原因是:%s\r\n", wstrMessage); } CloseHandle(hFile); } else { // 错误处理 wchar_t wstrMessage[MAXBYTE] = { 0 }; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(), 0, wstrMessage, MAXBYTE, nullptr); wprintf(L"打开文件失败,错误原因是:%s\r\n", wstrMessage); } DWORD dwCurTime = GetTickCount(); DWORD dwTimeElaped = dwCurTime - dwPrevTime; wprintf(L"共找到:%d 条符合条件的记录, 用时:%d毫秒。\r\n", dwCount, dwTimeElaped);}int main(){ wprintf(L"普通的文件读取方式,一个字节一个字节的读取:\r\n"); ReadFromFile(); wprintf(L"\r\n\r\n文件映射方式:\r\n"); ReadFromFileMap(); wprintf(L"\r\n\r\n一次性将整个内容读取到内存再处理的方式:\r\n"); ReadFromMemory(); system("pause"); return 0;}
结果如下:
需要注意的是:
- wprintf函数输出宽字节的问题,如果我们直接输出宽字节的中文字符,它会输出乱码,此时就需要对编码进行设置,使用setlocale(LC_ALL, “chs”)函数来设置,就能正确输出中文字符;
- MultiByteToWideChar的Windows API函数的使用需要注意;
- 使用FileMap时,因为我的内存可以一次全部将322兆的文件读进来,但是如果碰到计算机内存很小的计算机,有可能一次就读不进去322兆的文件,上面的方法就会有问题。正确的方式应该分多次来读取,这个方法下次再介绍。
- 从三中结果来看,使用文件映射时间最短,而一个字节一个字节的读取时间最长,一次将整个文件读进到内存的时间略大于文件映射,我们几乎可以认为多出来的大概500毫秒的时间是将整个文件读到内存所用与文件映射所用时间的差,所以总的来说,文件映射还是很块的。其实我们可以单独做一个实验,将只读到内存和文件映射的耗费时间。
下面的结果是指读取,不处理
从结果看出,文件映射几乎是不需要时间的,所以在以后的工作中,我们可以将很多事情都用文件映射来处理,比如:画界面,我们可以把bmp直接加载到FileMap中,然后通过hdc来画FileMap中的数据。其实任何的数据都可以加载到FileMap中,但是也不要滥用,比如很小的文件就不用了。
阅读全文
1 0
- Windows Practice_文件_内存映射(一)
- Windows Practice_内存映射_加载BMP
- Windows Practice_文件_文件分割器(一)
- Windows Practice_文件_文件分割器(二)
- Windows Practice_文件_文件分割器(三)
- Windows Practice_闹钟(一)_简易记事本
- Windows Practice_文件搜索器(二)_多线程调试
- Windows Practice_文件搜索器(三)_线程池
- Windows Practice_文件_文件基础操作
- Windows Practice_文件_注册表操作
- Windows Practice_文件搜索器(一)递归
- Windows Practice_文件搜索器(四)_封装文件扫描器
- Windows Practice_闹钟(二)_简易记事本
- Windows Practice_闹钟(六)_控件对象
- windows核心编程-内存映射文件(一)
- windows 内存映射文件
- windows 内存映射文件
- windows内存映射文件
- assert宏的使用
- 重新开始的php!
- python实现文件断点续传
- java和php的比较
- java练习题(1)、(2)、(3)
- Windows Practice_文件_内存映射(一)
- 《Python核心编程(第2版)》读书笔记(8)之析构(关键词:Python/析构/析构函数)
- [知了堂学习笔记]_牵线Eclipse和Tomcat第二篇 —— 安装Tomcat&&添加Tomcat到Eclipse
- Spatial Transformer Networks
- 梯度提升树GBDT原理
- linux-centos安装solr及通过zookeeper搭建solr集群
- Python学习入门
- [LeetCode] Add Two Numbers题解
- JAVA语言:求1+2!+3!+...+20!的和