首页 > 系统相关 >用C语言读取大文件的问题 内存映射

用C语言读取大文件的问题 内存映射

时间:2023-01-27 21:02:45浏览次数:45  
标签:文件 sName sValue 读取 TCHAR C语言 内存 NULL


Windows对文件的读写提供了很丰富的操作手段,如:

1. FILE *fp, fstearm
; (C/C++)
2. CFile, CStdioFile
; (MFC)
3. CreateFile, ReadFile
;(API)

用C语言读取大文件的问题 内存映射_null



在处理一般的文件(文本/非文本),这些足够了。然而在处理比较大的文件如

几十M, 几百M, 甚至上G的文件, 这时再用一般手段处理,系统就显的力不从心了


要把文件读出,再写进,耗费的是CPU利用率与内存以及IO的频繁操作。这显然是

令用户难以忍受的


为了解决这个吃内存,占CPU,以及IO瓶颈,windows核心编程提供了内存映射文件技术

(Maping File)


至于Maping File是什么原理,我不多说了,网上转载资源一箩筐,我只想从应用层

来考虑,怎样用这个技术,实现日常项目中的应用

举例来说:

可能项目中,会经常用到一些大量的常量,而这些大量常量用宏来替代写再源文件中

显然不可取,一般是写在文件中,给常量一些编号,通过编号来索引


一般文件比较小时候,常用做法也是先预读到内存中,毕竟从内存中读比从文件中读要快(IO操作的瓶颈)

比较好的做法,读到STL MAP 中去:

例如一个索引文件:

SEU07201213=汪洋中的一片叶子

JIANGSHENG=蒋晟

SEU07201214=CSDN

用C语言读取大文件的问题 内存映射_null

用C语言读取大文件的问题 内存映射_null

用C语言读取大文件的问题 内存映射_null

用C语言读取大文件的问题 内存映射_null


打开文件,解析=号,在解析方面有CString操作,strtok,strstr, boost 正则表达式匹配等等,但我比较喜欢

sscanf(szIndex, "%[^=]=%[^=]", sName, sValue);

sscanf(szIndex, "%[^=]=%s", sName, sValue);

fscanf(stream, "%[^=]=%[^=]", sName, sValue);

之类,

然后再定义一个map:

map<string, string> m_Map;

m_Map[sName] = sValue;


但是文件比较大的时候,笔者做过测试,用上面方法处理一个15M, 25万行的文本文件,占用内存非常

的高,达70多M,处理的速度也非常的慢,这还不包括回写到文件

这时,Maping File就派上用场了,这里处理大文件就抛弃了map的应用(因为容器占用很多内存)

而是直接利用字符指针来操作,不用其他封装,不多说了,请看示例:


#pragma warning(disable: 4786) 
#include <windows.h>
#include <stdio.h>
#include <iostream>
#include <string>

using namespace std;

string GetValue(const TCHAR *, const TCHAR *); //根据name得value
void main(int argc, char* argv[])
{
// 创建文件对象(C: est.tsr)
HANDLE hFile = CreateFile("C:/test.tsr", GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)

{
printf("创建文件对象失败,错误代码:%d ", GetLastError());
return;
}
// 创建文件映射对象
HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
if (hFileMap == NULL)

{
printf("创建文件映射对象失败,错误代码:%d ", GetLastError());
return;
}
// 得到系统分配粒度
SYSTEM_INFO SysInfo;
GetSystemInfo(&SysInfo);
DWORD dwGran = SysInfo.dwAllocationGranularity;
// 得到文件尺寸
DWORD dwFileSizeHigh;
__int64 qwFileSize = GetFileSize(hFile, &dwFileSizeHigh);
qwFileSize |= (((__int64)dwFileSizeHigh) << 32);
// 关闭文件对象
CloseHandle(hFile);
// 偏移地址
__int64 qwFileOffset = 0;
// 块大小
DWORD dwBlockBytes = 1000 * dwGran;
if (qwFileSize < 1000 * dwGran)
dwBlockBytes = (DWORD)qwFileSize;
if (qwFileOffset >= 0)

{
// 映射视图
TCHAR *lpbMapAddress = (TCHAR *)MapViewOfFile(hFileMap,FILE_MAP_ALL_ACCESS,
0, 0,
dwBlockBytes);
if (lpbMapAddress == NULL)

{
printf("映射文件映射失败,错误代码:%d ", GetLastError());
return;
}


//-----------------------访问数据开始-------------------------
cout<<GetValue(lpbMapAddress,"SEU07201213")<<endl;
getchar();
//-----------------------访问数据结束-------------------------

// 撤销文件映像
UnmapViewOfFile(lpbMapAddress);
}
// 关闭文件映射对象句柄
CloseHandle(hFileMap);
}
string GetValue(const TCHAR *lpbMapAddress, const TCHAR *sName)
{
string sValue; // 存放 = 后面的value值
TCHAR *p1 = NULL, *p2 = NULL; // 字符指针
if((p1 = strstr(lpbMapAddress,sName)) != NULL) // 查找sName出现位置
{
if(p2 = strstr(p1,"/r/n")) *p2 = '/0'; // 查找"/r/n"(换行)出现位置
sValue = p1+strlen(sName)+strlen("="); // 指针移动"sName"+"="之后
*p2 = '/r'; // 还原*p2值,因为不还原会改变原文件结构
}
return sValue;
}

用C语言读取大文件的问题 内存映射_null


 


以上实现了根据索引name匹配value的简单过程,经测试,同样25W行文件,匹配耗费1秒不到,且

不占本进程内存。

以上修改lpbMapAddress任意处值,也不需要重新回写到文件,真正是大大提高了文件读与写的效率

标签:文件,sName,sValue,读取,TCHAR,C语言,内存,NULL
From: https://blog.51cto.com/u_15942605/6024313

相关文章

  • vue图片读取
    <el-form-itemlabel="头像"prop="pass"><imgv-bind:src="imgSrc"style="width:100px;"><inputtype="file"ref="myfile"id="fileId......
  • Dotnet程序的内存与垃圾回收
    都知道程序运行时的变量是放在内存里的,从我们学c++就知道有析构函数 malloc,还有学c#的时候天天什么垃圾回收GC像背八股文样的,但是这个内存究竟能分配多少没有人想过......
  • Dotnet程序的内存与垃圾回收
    都知道程序运行时的变量是放在内存里的,从我们学c++就知道有析构函数 malloc,还有学c#的时候天天什么垃圾回收GC像背八股文样的,但是这个内存究竟能分配多少没有人想过......
  • AndroidBench&eMMC内存测试速度&Android
    提问: 问题:手机eMMC内存,我用AndroidBench/安兔兔/鲁大师测出来的速度很快,而自己写AndroidTool测试的速度确很慢,这是为什么呢?主要信息:   同样是SequenceWrite操作,An......
  • 范围内的完全数输出C语言代码
      #include<stdio.h>intmain(){ inti,j,n,he; i=1; printf("inputanumber:"); scanf("%d",&n); while(i<=n) { j=1;he=0; while(j<i) { if(i%j==0) ......
  • Python_argparse_读取命令行参数
    argparse模块是Python内置的用于命令项选项与参数解析的模块,可以方便地读取命令行参数。参考代码如下#1.导入模块importargparsedefformat_parser():#......
  • RTree源代码——C语言实现
    RTree源代码——C语言实现cheungmine一、什么是RTree“R树是B树向多维空间发展的另一种形式,它将空间对象按范围划分,每个结点都对应一个区域和一个磁盘页,非叶结点的磁盘页中......
  • SQLServer 2014 内存优化表
    内存优化表是SQLServer2014的新功能,它是可以将表放在内存中,这会明显提升DML性能。关于内存优化表,更多可参考两位大侠的文章:​​SQLServer2014新特性探秘(1)-内存数据库......
  • C语言实现一个简单的单向链表list
    C语言实现一个简单的单向链表listcheungmine用C语言实现一个简单实用的单向链表list,具有一定的实际意义。尤其我们不想使用STL里面的list<...>类的时候。我实现的这个list,结......
  • 基于Oracle OCI的数据访问C语言接口ORADBI
    基于OracleOCI的数据访问C语言接口ORADBI​​[email protected]​​Mar.22, 2008 ORADBI是我在OracleOCI(Oracle调用接口)基础上开发......