通过VC++内存映射修改大文件方法
内存映射文件的作用功能介绍
内存映射文件的作用功能介绍内存映射文件的主要用途:1.操作大文件 2.进程间大量数据共享,下面分别介绍如下:VC++中使用内存映射文件处理大文件引言文件操作是应用程序最为基本的功能之一,Win32 API和MFC均提供有支持文件处理的函数和类,常用的有Win32 API的CreateFile()、WriteFile()、ReadFile()和MFC提供的CFile类等。
一般来说,以上这些函数可以满足大多数场合的要求,但是对于某些特殊应用领域所需要的动辄几十GB、几百GB、乃至几TB的海量存储,再以通常的文件处理方法进行处理显然是行不通的。
目前,对于上述这种大文件的操作一般是以内存映射文件的方式来加以处理的,本文下面将针对这种Windows核心编程技术展开讨论。
内存映射文件内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,同时将物理存储器提交给此区域,只是内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而非系统的页文件,而且在对该文件进行操作之前必须首先对文件进行映射,就如同将整个文件从磁盘加载到内存。
由此可以看出,使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行I/O操作,这意味着在对文件进行处理时将不必再为文件申请并分配缓存,所有的文件缓存操作均由系统直接管理,由于取消了将文件数据加载到内存、数据从内存到文件的回写以及释放内存块等步骤,使得内存映射文件在处理大数据量的文件时能起到相当重要的作用。
另外,实际工程中的系统往往需要在多个进程之间共享数据,如果数据量小,处理方法是灵活多变的,如果共享数据容量巨大,那么就需要借助于内存映射文件来进行。
实际上,内存映射文件正是解决本地多个进程间数据共享的最有效方法。
内存映射文件并不是简单的文件I/O操作,实际用到了Windows的核心编程技术--内存管理。
所以,如果想对内存映射文件有更深刻的认识,必须对Windows操作系统的内存管理机制有清楚的认识,内存管理的相关知识非常复杂,超出了本文的讨论范畴,在此就不再赘述,感兴趣的读者可以参阅其他相关书籍。
内存映射文件
内存映射文件:内存映射文件有三种,第一种是可执行文件的映射,第二种是数据文件的映射,第三种是借助页面交换文件的内存映射.应用程序本身可以使用后两种内存映射.1.可执行文件映射:Windows在执行一个Win32应用程序时使用的是内存映射文件技术.系统先在进程地址空间的0x00400000以上保留一个足够大的虚拟地址空间(0x00400000以下是由系统管理的),然后把应用程序所在的磁盘空间作为虚拟内存提交到这个保留的地址空间中去(我的理解也就是说,虚拟内存是由物理内存和磁盘上的页面文件组成的,现在应用程序所在的磁盘空间就成了虚拟地址的页面文件).做好这些准备后,系统开始执行这个应用程序,由于这个应用程序的代码不在内存中(在页面文件中),所以在执行第一条指令的时候会产生一个页面错误(页面错误也就是说,系统所访问的数据不在内存中),系统分配一块内存把它映射到0x00400000处,把实际的代码或数据读入其中(系统分配一块内存区域,把它要访问的在页面文件中的数据读入到这块内存中,需在注意是系统读入代码或数据是一页一页读入的),然后可以继续执行了.当以后要访问的数据不在内存中时,就可以通过前面的机制访问数据.对于Win32DLL的映射也是同样,不过DLL文件应该是被Win32进程共享的(我想应该被映射到x80000000以后,因为0x80000000-0xBFFFFFFF是被共享的空间).当系统在另一个进程中执行这个应用程序时,系统知道这个程序已经有了一个实例,程序的代码和数据已被读到内存中,所以系统只需把这块内存在映射到新进程的地址空间即可,这样不就实现了在多个进程间共享数据了吗!然而这种共享数据只是针对只读数据,如果进程改写了其中的代码和数据,操作系统就会把修改的数据所在的页面复制一份到改写的进程中(我的理解也就是说共享的数据没有改变,进程改写的数据只是共享数据的一份拷贝,其它进程在需要共享数据时还是共享没有改写的数据),这样就可以避免多个进程之间的相互干扰.2.数据文件的内存映射:数据文件的内存映射原理与可执行文件内存映射原理一样.先把数据文件的一部分映射到虚拟地址空间的0x80000000 - 0xBFFFFFFF,但没有提交实际内存(也就是说作为页面文件),当有指令要存取这段内存时同样会产生页面错误异常.操作系统捕获到这个异常后,分配一页内存,映射内存到发生异常的位置,然后把要访问的数据读入到这块内存,继续执行刚才产生异常的指令(这里我理解的意思是把刚才产生异常的指令在执行一次,这次由于数据已经映射到内存中,指令就可以顺利执行过去),由上面的分析可知,应用程序访问虚拟地址空间时由操作系统管理数据在读入等内容,应用程序本身不需要调用文件的I/O函数(这点我觉得很重要,也就是为什么使用内存映射文件技术对内存的访问就象是对磁盘上的文件访问一样).3.基于页面交换文件的内存映射:内存映射的第三种情况是基于页面交换文件的.一个Win32进程利用内存映射文件可以在进程共享的地址空间保留一块区域(0x8000000 - 0xBFFFFFFF),这块区域与系统的页面交换文件相联系.我们可以用这块区域来存储临时数据,但更常见的做法是利用这块区域与其他进程通信(因为0x80000000以上是系统空间,进程切换只是私有地址空间,系统空间是所有进程共同使用的),这样多进程间就可以实现通信了.事实上Win32多进程间通信都是使用的内存映射文件技术,如PostMessage(),SentMessage()函数,在内部都使用内存映射文件技术.使用内存映射文件的方法:1.利用内存映射文件进行文件I/O操作:CreateFile()-->CreateFileMapping()-->MapViewOfFile()......2.利用内存映射文件实现Win32进程间通信:我只介绍两种常用的方法:第一种方法:两个进程使用同一个文件映射核心对象,打开各自的视图,或者父进程把自己创建的文件映射核心对象继承给子进程使用.这种方法比较安全有效.第二种方法:基于页面交换文件的内存映射对象.在调用CreateFileMapping()函数时,传递的文件句柄为0xFFFFFFFF,系统就从页面交换文件中提交物理内存,然后进程之间按照第一种方法进程通信.这种方法不用事先准备一个特殊的文件(也就是说不用事先调用CreateFile()返回一个文件的句柄),非常方便.。
VC6.0在32位机中对大数据量文件操作的扩展
POSI TI ON po s l
几种 不 同 情 况 的 处 理 方 法 。
境为 3 2 位 Wi n d o ws 系统 。
( 1 ) 首 先 我 们 把 需 要 操 作 的 数 据 文 件 时 文件F i l e l C o p y 。
并 且 还 要 针 对 一 些 数 据 结 构 不 能 操 作 大 型 格 式 的 大 数 据 量 文 件 的操 作 , 分 别 阐述 了 内存空间, 系 统 无 法 分配 内存 , 从 而导 致
m —f i 1 e.O P e n (f i 1 e N a m e,
中没 有考 虑 到大 数据 量 的 可能 性 , 对数 据块 i f ( mmf . Ma p F i l e ( t e mp Na me , TRU E, 大 小 的描 述 都 是 采 用 的整 型i n t 型或 长 整 型 F I L E ~ S HA R E — RE A D) )
信 息技 术
VC6. 0在 3 2位机 中对 大数 据量 文件 操作 的扩 展
褚 晓 冬 ( 中海 油 田服务股 份有 限公 司油 田技术研 究 院 河北 燕郊
0 6 5 2 0 1 )
摘 要 : 目前 , 随 着计算 机在 各个 产 业部 门的逐 渐普 及 、 计算机 运算 能 力的逐 步提 高 以及各 种新 型需 求的诞 生 , 对文 件存 储 以及访 问 的需求也 随之 升高 , 人 们已经不 能满足 于基 于兆叛 的数据文 件的 访问 , 更大 的数 据文 件的访 问和 支持 能 力对开 发人 员提 出 了更 高的要 求, 但是 , 受计算 机硬 件 条件 , 系统软 件 的版 本 以及软 件 开发 版本 的 约束 , 我 们并 不 能大 刀 阔斧的 对软 件进 行彻 底修 改 , 否则会 对软 件的兼容 性遗 成非 常 严重 的危 害 , 因此 我们 需要针 对不 同情 况来 分剐对 各种 大型数据进 行遍 历 , 从 而保 证软件 在不 同配置 的计算机 上
汇编修改文件操作
汇编修改文件操作想一想,如果你要写一个加密程序,或者病毒程序,都需要对文件进行修改(写操作)。
在dos下,系统提供有相应的功能调用来完成这样的操作,如:“打开文件\移动指针\读文件\写文件\关闭文件”,在windows下,系统也提供有相应的Api函数。
如“CreateFile\SetFilePointer\ReadFile\WriteFile\SetEndOfFile\CloseHandle”等,利用这些编程和dos下没什么两样,这里就不再多说啦!咱们今天要用的是利用“内存映射文件”来操作。
简单的说就是把文件内容映射到一个内存块,改变这块内存的内容就是改变文件的内容,系统可提供的这块内存巨大、平坦,操作起来真是方便!这种方法要用到“CreateFile/CreatFileMapping/MapViewOfFile/UnmapViewOfFile/CloseHandle”,具体使用参考“Win32 Developer's References”。
俺也是刚看,不敢乱说,嘿嘿嘿。
--------------------------------------------------------------;例:打开一个已存在的文件并修改,建议文件具有一定的大小,比如80H字节。
;文件名:12.asm.386.Model Flat, StdCallOption Casemap :None;---------------------------------------------------------Include windows.incInclude kernel32.incIncludeLib kernel32.libModifyFile PROTO :LPSTR.dataMyFile db 'd:\masm7\MyTest',0 ;文件MyTest必须存在,若不存在,程序将什么也不做M1 db 'Good morning',0 ;将写到文件中的字符串M2 db 'Good afternoon',0M3 db 'Good evening',0;---------------------------------------------------------.data?hFile dd ?hMap dd ?pMapAddr dd ?;---------------------------------------------------------.codeSTART:invoke CreateFile, \ ;打开文件,该函数具有多种功能ADDR MyFile,\ ;指向要打开的文件名字符串GENERIC_READ or GENERIC_WRITE ,\ ;打开的文件具有读写的权限FILE_SHARE_READ or FILE_SHARE_WRITE,\ ;别人也可读写此文件NULL, \ ;95下不用OPEN_EXISTING, \ ;要打开的文件必须存在FILE_ATTRIBUTE_NORMAL,\ ;文件的属性NULL ;95下必须是NULL.if eax!=INV ALID_HANDLE_V ALUE ;判断文件是否已正常打开mov hFile, eax ;保存文件句柄invoke CreateFileMapping, \ ;creates file-mapping object for the specified file.hFile, \ ;Identifies the file from which to create a mapping objectNULL, \ ;ignoredPAGE_READWRITE, \ ;access0, \ ;high-order 32 bits of the maximum size0, \ ;low-order 32 bits of the maximum sizeNULL ;the mapping object is created without a name.if eax!=NULL ;mov hMap,eax ;the return value is a handle to the file-mapping objectinvoke MapViewOfFile,hMap,FILE_MAP_WRITE,0,0,NULL ;映射文件到内存 .if eax!=NULLmov pMapAddr,eax ;保存返回的内存块首地址invoke ModifyFile,pMapAddr ;修改内存块内容invoke UnmapViewOfFile,pMapAddr ;解除文件映射.endifinvoke CloseHandle,hMap ;关闭内存映射文件.endifinvoke CloseHandle, hFile ;关闭文件.endifinvoke ExitProcess,0 ;结束程序;修改内存块的内容,就相当于修改文件的内容ModifyFileproc uses ebx esi edi,lpBufferAddress:LPSTRmov edi,lpBufferAddress ;取内存块地址invoke lstrcpy,edi,addr M1 ;修改内存块内容add edi,40h ;调整地址(随意)invoke lstrcpy,edi,addr M2 ;修改add edi,240hinvoke lstrcpy,edi,addr M3retModifyFileendpEND START----------------------------------------------------------------------注意:0、程序运行后无任何提示,只可从被修改的文件上看变化1、第39、40行的值都是0,这样,内存映射文件的大小就正好取文件的实际大小2、可以看到,第62、63行的修改并没起作用,因为文件没有这样大。
windows 读取超大文件到内存的方法
windows 读取超大文件到内存的方法以Windows读取超大文件到内存的方法在日常的计算机使用过程中,我们经常会遇到需要读取超大文件的情况。
然而,由于超大文件的体积过大,直接将其读取到内存中可能会导致内存溢出或系统崩溃的问题。
本文将介绍一种在Windows系统下读取超大文件到内存的方法,以避免出现这些问题。
一、使用流式读取在处理超大文件时,我们可以使用流式读取的方式,逐行读取文件内容,而不是一次性将整个文件读入内存。
这种方式可以大大减少内存的占用,提高程序的运行效率。
在Windows系统下,我们可以使用Python编程语言来实现流式读取超大文件的操作。
首先,我们需要安装Python的相关环境。
然后,使用以下代码来实现文件的流式读取:```pythonwith open('file.txt', 'r') as file:for line in file:# 处理每一行的代码```这段代码中,我们使用`open()`函数打开文件,并以只读模式(`'r'`)读取文件内容。
然后,通过`for`循环逐行读取文件内容,并在每一行进行相应的处理。
通过这种方式,我们可以将超大文件的内容逐行读取到内存中,而不会占用过多的内存空间。
二、使用缓冲区除了流式读取,我们还可以使用缓冲区的方式来读取超大文件。
缓冲区是一种临时存储区域,可以将部分文件内容读入内存,然后逐步处理。
这样可以减少对内存的占用,提高读取文件的效率。
在Windows系统下,我们可以使用C#编程语言来实现使用缓冲区读取超大文件的操作。
首先,我们需要在代码中引入`System.IO`命名空间。
然后,使用以下代码来实现文件的缓冲区读取:```csharpusing (var fileStream = new FileStream("file.txt", FileMode.Open)){using (var streamReader = new StreamReader(fileStream, Encoding.UTF8, true, 1024)){while (!streamReader.EndOfStream){var line = streamReader.ReadLine();// 处理每一行的代码}}}```这段代码中,我们使用`FileStream`和`StreamReader`类来实现文件的缓冲区读取。
VC++命令行操作
VC++命令行操作cl.exe所在的文件夹里面有一个批处理叫做VSVAR32.BAT首先运行它一次,你就可以用cl.exe来编译你的代码了。
CL.exe 是控制Microsoft C 和C++ 编译器与链接器的32 位工具。
编译器产生通用对象文件格式(COFF) 对象(.obj) 文件。
链接器产生可执行文件(.exe) 或动态链接库文件(DLL)。
注意,所有编译器选项都区分大小写。
若要编译但不链接,请使用/c。
使用NMAKE 生成输出文件。
使用BSCMAKE 支持类浏览。
以下是一个完整的编译器选项分类列表。
优化选项作用/O1 创建小代码/O2 创建快速代码/Oa 假设没有别名/Ob 控制内联展开/Od 禁用优化/Og 使用全局优化/Oi 生成内部函数/Op 改善浮点数一致性/Os 代码大小优先/Ot 代码速度优先/Ow 假定在函数调用中使用别名/Ox 使用最大优化(/Ob1gity /Gs)/Oy 省略框架指针代码生成选项作用/clr 启用C++ 的托管扩展并产生在公共语言运行库上运行的输出文件/EH 指定异常处理模型/G3 优化代码以优选386 处理器。
在Visual C++ 5.0 中已经停用,编译器将忽略此选项/G4 优化代码以优选486 处理器。
在Visual C++ 5.0 中已经停用,编译器将忽略此选项/G5 优化代码以优选Pentium/GB 与/G6 等效;将_M_IX86 的值设置为600/Gd 使用__cdecl 调用约定/Ge 激活堆栈探测/GF/GF 启用字符串池/GH 调用挂钩函数_penter/GH 调用挂钩函数_pexit/GL 启用全程序优化/Gm 启用最小重新生成/Gr 启用运行时类型信息(RTTI)/Gr 使用__fastcall 调用约定/GS 控制堆栈探测/GT 支持使用静态线程本地存储区分配的数据的纤程安全/GX 启用同步异常处理/Gy 启用函数级链接/GZ 使用__stdcall 调用约定/MD 使用MSVCRT.lib 创建多线程DLL/MDd 使用MSVCRTD.lib 创建调试多线程DLL/ML 使用LIBC.lib 创建单线程可执行文件/MLd 使用LIBCD.lib 创建调试单线程可执行文件/MT 使用LIBCMT.lib 创建多线程可执行文件/MTd 使用LIBCMTD.lib 创建调试多线程可执行文件输出文件选项作用/FA/FA 创建列表文件设置列表文件名/Fd 重命名程序数据库文件/Fe 重命名可执行文件/Fm 创建映射文件/Fo 创建对象文件/Fp 指定预编译头文件名/FR/FR 生成浏览器文件/Fx 将插入的代码与源文件合并调试选项作用/GS 缓冲区安全检查/GZ 与/RTC1 相同/RTC 启用运行时错误检查/Wp64 检测64 位可移植性问题/Yd 将完整的调试信息放在所有对象文件中/Yl 创建调试库时插入PCH 引用/Z7 生成与C 7.0 兼容的调试信息/Zd 生成行号/Zi 生成完整的调试信息预处理器选项作用/AI 指定在解析传递到#using 指令的文件引用时搜索的目录/c 在预处理期间保留注释/D 定义常数和宏/E 将预处理器输出复制到标准输出/EP 将预处理器输出复制到标准输出/Fl 预处理指定的包含文件/FU 强制使用文件名,就像它已被传递到#using 指令一样/I 在目录中搜索包含文件/P 将预处理器输出写入文件/U 移除预定义宏/U 移除所有的预定义宏/X 忽略标准包含目录/ZI 将调试信息包含在与“编辑并继续”兼容的程序数据库中语言选项作用/noBool 取消C++ bool、true 和false 关键字/vd 取消或启用隐藏的vtordisp 类成员/vmb 对指向成员的指针使用最佳的基/vmg 对指向成员的指针使用完全一般性/vmm 声明多重继承/vms 声明单一继承/vmv 声明虚拟继承/Za 禁用语言扩展/Zc 在/Ze 下指定标准行为/Ze 启用语言扩展/Zg 生成函数原型/Zl 从 .obj 文件中移除默认库名/Zp n 封装结构成员/Zs 只检查语法链接选项作用/F 设置堆栈大小/LD 创建动态链接库/LDd 创建调试动态链接库/link 将指定的选项传递给LINK/MD 使用MSVCRT.lib 编译以创建多线程DLL/MDd 使用MSVCRTD.lib 编译以创建调试多线程DLL/ML 使用LIBC.lib 编译以创建单线程可执行文件/MLd 使用LIBCD.lib 编译以创建调试单线程可执行文件/MT 使用LIBCMT.lib 编译以创建多线程可执行文件/MTd 使用LIBCMTD.lib 编译以创建调试多线程可执行文件预编译头选项作用/Y- 忽略当前生成中的所有其他预编译头编译器选项/Yc 创建预编译头文件/Yd 将完整的调试信息放在所有对象文件中/Yu 在生成期间使用预编译头文件/YX 自动处理预编译头杂项选项作用@ 指定响应文件/? 列出编译器选项/c 编译但不链接/H 限制外部(公共)名称的长度/HELP 列出编译器选项/J 更改默认的char 类型/NOLOGO 取消显示登录版权标志/QI0f 确保Pentium 0F 指令没有问题/QIfdiv FDIV、FPREM、FPTAN 和FPATAN 指令有缺陷的Intel Pentium 微处理器的变通方法QIfist 当需要从浮点类型转换为整型时取消Helper 函数_ftol 的调用/showIncludes 在编译期间显示所有包含文件的列表/Tc/Tc 指定C 源文件/Tp/Tp 指定C++ 源文件/V 设置版本字符串/w 设置警告等级/w 禁用所有警告/Wall 启用所有警告,包括默认情况下禁用的警告/WL 在从命令行编译C++ 源代码时启用错误信息和警告消息的单行诊断/Zm 设置编译器的内存分配限制CL 命令行使用下列语法:CL [option...] file... [option | file]... [lib...] [@command-file] [/link link-opt...]下表说明CL 命令的输入项意义option 一个或多个CL 选项。
修改core file size-概述说明以及解释
修改core file size-概述说明以及解释1.引言1.1 概述在撰写此篇长文之前,我们首先需要了解什么是core file size以及为什么需要修改它。
Core file size指的是在发生程序崩溃或异常退出时,系统生成的core文件的大小限制。
正常情况下,core文件包含了程序崩溃时的内存状态、堆栈信息以及其他调试相关的数据,这对于开发人员来说是非常有价值的。
通过分析core文件,开发人员可以更容易地定位和解决问题。
默认情况下,操作系统对core文件的大小有一定的限制。
一旦core 文件大小达到了限制,系统会停止继续生成core文件,从而保护系统的稳定性和性能。
然而,在某些情况下,我们可能需要修改core file size 的限制,以便能够生成更大的core文件,以提供更详细的调试信息。
本文将讨论如何修改core file size的方法,以及对此操作可能带来的意义和影响。
在修改core file size之前,我们需要了解系统的具体配置和限制,并采取相应的步骤来修改系统设置。
同时,我们还将讨论可能的风险和注意事项,以确保在修改core file size时不会对系统的稳定性和安全性产生负面影响。
通过对core file size的修改,开发人员可以更充分地利用core文件提供的调试信息来定位和解决程序的问题。
然而,这也需要在操作系统的限制下谨慎操作,以确保系统的稳定性和性能不受影响。
在深入探讨修改core file size的方法之前,我们需要先了解当前系统的配置和限制,以便做出明智的决策并采取必要的措施。
接下来,本文将详细介绍好几种修改core file size的方法,并逐一讨论它们的优缺点和适用场景。
这将帮助读者根据实际需求选择最合适的方法来修改core file size。
在总结部分,我们将对本文的主要内容进行回顾,并强调修改core file size的重要性和潜在影响。
VC6.0在32位机中对大数据量文件操作的扩展
VC6.0在32位机中对大数据量文件操作的扩展摘要:目前,随着计算机在各个产业部门的逐渐普及、计算机运算能力的逐步提高以及各种新型需求的诞生,对文件存储以及访问的需求也随之升高,人们已经不能满足于基于兆级的数据文件的访问,更大的数据文件的访问和支持能力对开发人员提出了更高的要求,但是,受计算机硬件条件、系统软件的版本以及软件开发版本的约束,我们并不能大刀阔斧的对软件进行彻底修改,否则会对软件的兼容性造成非常严重的危害,因此我们需要针对不同情况来分别对各种大型数据进行遍历,从而保证软件在不同配置的计算机上能够顺利运行。
关键词:新型需求彻底修改遍历中图分类号:tp3 文献标识码:a 文章编号:1672-3791(2013)01(b)-0024-01在石油及矿产勘探领域,经常使用不同方式对地层进行探测,随着探测手段日益增强,衍生出的数据量也越来越大,从早期的几十兆到现在的几个g的级别,不仅对计算机的要求日益提高,同时对软件开发人员也提出了更高的要求:开发人员要花费大量精力来优化内存以及cpu的使用,并且还要针对一些数据结构不能操作大型数据进行扩展。
本文针对某油田测井数据格式的大数据量文件的操作,分别阐述了几种不同情况的处理方法。
本程序是基于vc6.0开发的,其运行环境为32位windows系统。
1 修改数据描述格式首先,我们需要面对的是数据格式不能满足需求的问题,对所有标识文件数据块大小的字段进行类型的修改,原有的代码中没有考虑到大数据量的可能性,对数据块大小的描述都是采用的整型int型或长整型long格式,由于采用的是有符号整型,所以其只能标识-2147483648~2147483648的文件块大小,这对于一般的线性数据块大小是足够的,但是对于大范围的波列数据以及矩阵类型数据的描述就捉襟见肘了。
本程序采用了一种叫做ulonglong的据格式,该格式为无符号64位数据格式,理论上可以达到0~18446744073709551616的存储长度,这样的话对于任意可能存在的数据长度,该格式都是足够描述的。
linux c 快速写大文件的策略
linux c 快速写大文件的策略Linux C 是一种在 Linux 环境下使用 C 语言进行编程的技术。
在某些应用场景中,我们需要快速地生成大文件。
本文将介绍一些在Linux C 中快速写大文件的策略,以帮助读者更好地理解和应用这些技术。
在Linux C 中,我们可以使用文件操作函数来进行文件的读写操作。
为了快速地写入大文件,我们可以采用以下策略:1. 使用缓冲区:在写入大文件时,直接使用文件操作函数进行写入是非常低效的。
为了提高写入速度,我们可以使用缓冲区来暂存待写入的数据。
通过一次性写入一块较大的数据,可以减少写入操作的次数,从而提高写入速度。
可以使用`fwrite` 函数来一次性写入缓冲区中的数据。
2. 调整文件指针:在写入大文件时,我们可以通过调整文件指针的位置来实现快速写入。
通过调用`fseek` 函数,我们可以将文件指针移动到指定的位置,然后进行写入操作。
这样可以避免每次写入都从文件的开头进行操作,提高写入速度。
3. 并行写入:在某些情况下,我们可以将大文件分割成多个小文件,并使用多个线程或进程同时进行写入操作。
通过并行写入,可以充分利用系统资源,提高写入速度。
在Linux C 中,可以使用线程库或进程库来实现并行写入操作。
4. 优化IO 操作:在进行文件写入操作时,可以采用一些优化技巧来提高写入速度。
例如,可以使用非阻塞 IO 或异步 IO 来实现并行写入操作。
另外,可以设置文件描述符的属性,如缓冲区大小、文件锁等,来优化写入操作。
5. 写入数据压缩:在写入大文件时,可以考虑对待写入的数据进行压缩操作。
通过压缩数据,可以减少写入的数据量,从而提高写入速度。
在 Linux C 中,可以使用压缩库来实现数据压缩操作。
通过以上几种策略的组合应用,我们可以在Linux C 中快速地写入大文件。
在实际应用中,我们可以根据具体的需求和场景选择合适的策略。
同时,我们还需要注意以下几点:1. 写入速度与硬件性能有关:在进行大文件写入时,除了优化写入的策略,硬件性能也是一个重要因素。
VC利用内存映射文件处理大文件
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { TRACE("创建文件对象失败,错误代码:%d\r\n", GetLastError()); return; } // 创建文件映射对象 HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL); if (hFileMap == NULL) { TRACE("创建文件映射对象失败,错误代码:%d\r\n", 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 = dwGran; while (qwFileSize > 0) { // 映射视图 if (qwFileSize < dwGran) dwBlockBytes = (DWORD)qwFileSize; LPBYTE lpbMapAddress = (LPBYTE)MapViewOfFile(hFileMap,FILE_MAP_ALL_ACCESS, (DWORD)(qwFileOffset >> 32), (DWORD)(qwFileOffset & 0xFFFFFFFF), dwBlockBytes); if (lpbMapAddress == NULL) { TRACE("映射文件映射失败,错误代码:%d\r\n", GetLastError()); return; } // 对映射的视图进行访问 for(DWORD i = 0; i < dwBlockBytes; i++) {
大文件读取解决方案
大文件读取解决方案1.分块读取:将文件分割为多个块进行读取。
可以设置一个固定的块大小,逐步读取每个块的数据。
这种方法适用于文件无序的情况,但需要借助文件指针进行定位。
2.缓存读取:使用缓冲区来存储部分文件内容,通过循环读取小块数据并累计存储在缓冲区中。
随着缓冲区的数据被处理完,再读取下一块数据。
这种方法可以减少内存的占用,提高读取效率。
3. 内存映射文件:通过将文件映射到内存中,可以像访问内存一样访问文件内容。
可以使用mmap函数(在Linux环境下)或CreateFileMapping函数(在Windows环境下)将文件映射到内存中,并使用指针进行操作和读取。
4.多线程读取:将文件分割为多个部分,每个线程负责读取一个部分的数据。
可以有效利用多核处理器的并行能力,提高读取速度。
需要注意进行线程同步和数据合并。
5.压缩文件读取:如果文件内容可以压缩,可以先将文件进行压缩处理,然后在读取时进行解压缩操作。
这样可以减小文件大小,提高读取效率。
6.使用流处理:使用流来逐行读取文件内容,而不是一次性读取整个文件。
这种方法可以减少内存的占用,并且适用于处理大文件中的一行或一部分内容。
7.使用数据库:将文件内容导入数据库,然后通过数据库的查询语句进行读取操作。
数据库可以有效地管理大量数据,并提供高效的查询功能。
8. 使用专业的大文件读取工具:一些专门为大文件读取设计的工具,例如Hadoop、Spark等,可以处理大规模的数据集,并提供高性能的文件读取能力。
在选择解决方案时,需要考虑文件的具体情况和应用需求。
不同的解决方案适用于不同的场景,可以根据实际情况选择最合适的方法。
同时,也可以结合多种方法进行优化和改进,以提高大文件读取的效率和可靠性。
大文件读取解决方案
大文件读取解决方案在处理大文件读取的过程中,主要涉及到以下几个方面的问题:文件大小、内存限制、IO性能以及文件格式等。
针对这些问题,可以采取以下解决方案:1.分块读取:将大文件切割为多个小块进行读取和处理。
通过逐块读取文件可以一定程度上减少内存的使用量。
可以使用文件指针定位到需要读取的位置,然后读取指定大小的数据块。
2. 使用缓冲区:在读取大文件时,可以利用缓冲区来减少IO次数,从而提高IO性能。
可以使用缓冲流(BufferedReader、BufferedInputStream等)进行读取,设定合理的缓冲区大小,以提高读取效率。
3.多线程读取:在多核CPU上可以使用多线程并行读取文件,提高读取速度。
将文件切割成多个块,并使用多个线程同时读取和处理。
可以利用线程池来管理线程的创建和销毁,控制并发数,避免资源浪费和线程频繁切换的开销。
4. 内存映射文件:通过使用内存映射文件,将大文件映射到内存中,可以直接在内存中进行读取操作,避免频繁的IO操作。
内存映射文件可以使用NIO中的FileChannel类的map(方法来实现。
5.使用外部存储:如果内存不能完全加载大文件,可以考虑使用外部存储进行读取和处理,如数据库等。
可以将大文件拆分为小文件,存储在数据库中,再进行读取和处理,减少内存的压力。
6.改变文件格式:如果可能的话,可以考虑改变文件的格式,减小文件的大小。
例如,可以使用压缩算法对文件进行压缩,减小文件的体积,然后再解压缩进行读取和处理。
7. 使用专用的文件处理工具:可以使用专门的大文件处理工具,如Hadoop、Spark等,这些工具提供了分布式处理的能力,可以将大文件划分为多个块,分发到不同的节点上进行处理,大大加快处理速度。
8.增加硬件资源:如果处理大文件的性能问题持续存在,可以考虑增加硬件资源,如更大的内存、更快的磁盘等,以提升读取和处理性能。
总结起来,大文件读取需要综合考虑文件大小、内存限制、IO性能和文件格式等因素,可以采取分块读取、使用缓冲区、多线程读取、内存映射文件等方式来解决问题。
c语言读取大文件
CreateFileMapping的MSDN翻译和使用心得测试创建和打开文件映射的时候老是得到"句柄无效"的错误, 仔细看了MSDN以后才发觉是函数认识不透, 这里把相关的解释翻译出来HANDLE CreateFileMapping(HANDLE hFile, //物理文件句柄LPSECURITY_ATTRIBUTES lpAttributes, //安全设置DWORD flProtect, //保护设置DWORD dwMaximumSizeHigh, //高位文件大小DWORD dwMaximumSizeLow, //低位文件大小LPCTSTR lpName //共享内存名称);1) 物理文件句柄任何可以获得的物理文件句柄, 如果你需要创建一个物理文件无关的内存映射也无妨,将它设置成为0xFFFFFFFF(INVALID_HANDLE_VALUE)就可以了.如果需要和物理文件关联, 要确保你的物理文件创建的时候的访问模式和"保护设置"匹配, 比如: 物理文件只读, 内存映射需要读写就会发生错误. 推荐你的物理文件使用独占方式创建.如果使用INVALID_HANDLE_VALUE, 也需要设置需要申请的内存空间的大小, 无论物理文件句柄参数是否有效, 这样CreateFileMapping 就可以创建一个和物理文件大小无关的内存空间给你, 甚至超过实际文件大小, 如果你的物理文件有效, 而大小参数为0, 则返回给你的是一个和物理文件大小一样的内存空间地址范围. 返回给你的文件映射地址空间是可以通过复制, 集成或者命名得到, 初始内容为0.2) 保护设置就是安全设置, 不过一般设置NULL就可以了, 使用默认的安全配置. 在win2k下如果需要进行限制, 这是针对那些将内存文件映射共享给整个网络上面的应用进程使用是, 可以考虑进行限制.3) 高位文件大小弟兄们, 我想目前我们的机器都是32位的东东, 不可能得到超过32位进程所能寻址的私有32位地址空间, 一般还是设置0吧, 我没有也不想尝试将它设置超过0的情况.4) 低位文件大小这个还是可以进行设置的, 不过为了让其他共享用户知道你申请的文件映射的相关信息, 我使用的时候是在获得的地址空间头部添加一个结构化描述信息, 记录内存映射的大小, 名称等, 这样实际申请的空间就比输入的增加了一个头信息结构大小了, 我认为这样类似BSTR的方式应该是比较合理的.5) 共享内存名称这个就是我今天测试的时候碰壁的祸根, 因为为了对于内存进行互斥访问, 我设置了一个互斥句柄, 而名称我选择和命名共享内存同名, 之下就是因为他们使用共同的namespace导致了错误, 呵呵.7) 调用CreateFileMapping的时候GetLastError的对应错误ERROR_FILE_INVALID 如果企图创建一个零长度的文件映射, 应有此报ERROR_INVALID_HANDLE 如果发现你的命名内存空间和现有的内存映射, 互斥量, 信号量, 临界区同名就麻烦了ERROR_ALREADY_EXISTS 表示内存空间命名已经存在8) 相关服务或者平台的命名保留Terminal Services:命名可以包含"Global\" 或者"Local\" 前缀在全局或者会话名空间初级文件映射. 其他部分可以包含任何除了(\)以外的字符, 可以参考Kernel Object Name Spaces.Windows 2000 or later:如果Terminal Services 没有运行"Global\" 和"Local\" 前缀的特殊含义就被忽略了CreateFileMapping 函数(转载)内存映射API函数CreateFileMapping创建一个有名的共享内存:HANDLE CreateFileMapping(HANDLE hFile, // 映射文件的句柄,//设为0xFFFFFFFF以创建一个进程间共享的对象LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // 安全属性DWORD flProtect, // 保护方式DWORD dwMaximumSizeHigh, //对象的大小DWORD dwMaximumSizeLow,LPCTSTR lpName // 必须为映射文件命名);与虚拟内存类似,保护方式可以是PAGE_READONLY或是PAGE_READWRITE。
内存映射文件原理及实例
内存映射文件原理及实例本课中我们将要讲解内存映射文件并且演示如何运用它。
您将会发现使用内存映射文件是非常简单的。
理论:如果您仔细地研究了前一课的例子,就会发现它有一个严重的缺陷:如果您想读的内容大于系统分配的内存块怎么办?如果您想搜索的字符串刚好超过内存块的边界又该如何处理?对于第一个问题,您也许会说,只要不断地读就不解决了吗。
至于第二个问题,您又会说在内存块的边界处做一些特别的处理,譬如放上一些标志位就可以了。
原理上确实是行得通,但是这随问题复杂程度加深而显得非常难以处理。
其中的第二个问题是有名的边界判断问题,程序中许许多多的错误都是由此引起。
想一想,如果我们能够分配一个能够容纳整个文件的大内存块该多好啊,这样这两个问题不都迎刃而解了吗?是的,WIN32的内存映射文件确实允许我们分配一个装得下现实中可能存在的足够大的文件的内存。
利用内存映射文件您可以认为操作系统已经为您把文件全部装入了内存,然后您只要移动文件指针进行读写即可了。
这样您甚至不需要调用那些分配、释放内存块和文件输入/输出的API函数,另外您可以把这用作不同的进程之间共享数据的一种办法。
运用内存映射文件实际上没有涉及实际的文件操作,它更象为每个进程保留一个看得见的内存空间。
至于把内存映射文件当成进程间共享数据的办法来用,则要加倍小心,因为您不得不处理数据的同步问题,否则您的应用程序也许很可能得到过时或错误的数据甚至崩溃。
本课中我们将主要讲述内存映射文件,将不涉及进程间的同步。
WIN32中的内存映射文件应用非常广泛,譬如:即使是系统的核心模块---PE格式文件装载器也用到了内存映射文件,因为PE格式的文件并不是一次性加载到内存中来的,譬如他它在首次加载时只加载必需加载的部分,而其他部分在用到时再加载,这正好可以利用到内存映射文件的长处。
实际中的大多数文件存取都和P E加载器类似,所以您在处理该类问题时也应该充分利用内存映射文件。
内存映射文件本身还是有一些局限性的,譬如一旦您生成了一个内存映射文件,那么您在那个会话期间是不能够改变它的大小的。
内存映射文件的工作原理及使用方法
内存映射文件的工作原理及使用方法内存映射文件(Memory-mapped files)是一种将文件映射到内存的机制,它允许应用程序直接访问磁盘上的文件,而无需进行显式的读写操作。
在内存映射文件中,操作系统将文件的一些区域映射到了进程的虚拟内存空间,从而让应用程序可以像访问内存一样访问文件的内容。
内存映射文件的工作原理及使用方法如下:工作原理:1. 打开文件:应用程序首先使用标准的文件操作函数(如open()打开需要映射的文件。
在打开文件时,操作系统会为该文件维护一个文件描述符(File Descriptor)以及其他相关信息。
2. 创建映射:应用程序使用操作系统提供的内存映射函数(如mmap()将文件的一些区域映射到进程的虚拟内存空间中。
该区域通常以页为单位进行映射,即一个或多个连续的页被映射为一段连续的虚拟内存区域。
3.访问文件:一旦映射创建成功,应用程序就可以像访问内存一样访问文件的内容。
读文件时,应用程序直接读取虚拟内存中的数据,操作系统会自动将数据从磁盘读取到内存中;写文件时,应用程序直接修改虚拟内存中的数据,操作系统也会自动将数据写回磁盘。
4.同步数据:内存映射文件中的数据是与磁盘文件保持同步的。
当应用程序对映射区域进行修改时,操作系统会将数据缓存到内存中,并在适当的时机进行写回磁盘,以保证文件的一致性。
使用方法:1. 准备文件:首先需要准备一个需要映射的文件。
可以通过标准的文件操作函数(如open(、write()创建或修改文件。
2. 打开映射:使用内存映射函数(如mmap()将文件的一些区域映射到虚拟内存中。
需要指定映射的起始位置、映射的长度、映射的权限等参数。
3.访问文件:通过访问虚拟内存中的映射区域,可以读写文件的内容。
可以使用指针操作、数组操作或其他方式来访问映射区域中的数据。
4. 同步数据:在需要时,可以使用内存同步函数(如msync()将内存中修改的数据写回磁盘,以保证文件的一致性。
vc++修改pe
在 网上有很多关于PE文件格式的说明,讲得最多莫过于IMAGE_DOS_HEADER、IMAGE_NT_HEADERS、 IMAGE_SECTION_HEADER、等。而对于节的介绍最多的,也莫过于函数引入引出节。而关于资源节.rsrc的介绍则少之又少。好了,废话少 说。
1、 peSource.exe (从此文件中提取图标)
2、 peDesc.exe (将图标写入此文件)
第二部,分别打开这两个文件,hFileSource设为只读,hFileDesc设为可写。
HANDLE hFileSource;
HANDLE hFileDesc;
打开后,大家最常用的莫过于文件映射,这里为方便与直观,我们直接把文件读到一个内存块中。
// with this directory entry. If the name of the entry is an actual text
// string instead of an integer Id, then the high order bit of the name field
// subdirectory), then the high order bit of the offset field will be
// set to indicate this. Otherwise the high bit is clear and the offset
// field points to a resource data entry.
} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;
使用MFC读取大文件
// 将文件数据映射到进程的地址空间
PBYTE pbFile = (PBYTE)MapViewOfFile(hFileMapping,
FILE_MAP_ALL_ACCESS,
(DWORD)(qwFileOffset>>32), (DWORD)(qwFileOffset&0xFFFFFFFF), dwBytesInBlock);
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile);
函数CreateFile()即使是在普通的文件操作时也经常用来创建、打开文件,在处理内存映射文件时,该函数来创建/打开一个文件内核对象,并将其句柄返回,在调用该函数时需要根据是否需要数据读写和文件的共享方式来设置参数dwDesiredAccess和dwShareMode,错误的参数设置将会导致相应操作时的失败。
VC读取大文件
VC++中使用内存映射文件处理大文件
摘要: 本文给出了一种方便实用的解决大文件的读取、存储等处理的方法,并结合相关程序代码对具体的实现过程进行了介绍。
引言
文件操作是应用程序最为基本的功能之一,Win32 API和MFC均提供有支持文件处理的函数和类,常用的有Win32 API的CreateFile()、WriteFile()、ReadFile()和MFC提供的CFile类等。一般来说,以上这些函数可以满足大多数场合的要求,但是对于某些特殊应用领域所需要的动辄几十GB、几百GB、乃至几TB的海量存储,再以通常的文件处理方法进行处理显然是行不通的。目前,对于上述这种大文件的操作一般是以内存映射文件的方式来加以处理的,本文下面将针对这种Windows核心编程技术展开讨论。
如何修改堆栈的大小
如何修改堆栈的⼤⼩内存的读取速度显然较硬盘要快的多,当做程序时遇到⼤规模数据的频繁存取的时候,开辟内存空间就更显得重要了!⼀般来说,我们所⽤的内存有栈和堆之分,其它的我们很少控制,栈的速度快,但是空间⼩,不灵活;⽽堆的空间⼏乎可以满⾜任何要求,灵活,但是相对的速度要慢了很多,并且在vc中堆是⼈为控制的,new了就要delete,否则很容易产⽣内存泄露等问题。
VC++默认的栈空间是1M,将程序栈空间定义得⼤⼀点,有两个⽅法更改⽅法⼀:link时⽤/STACK指定它的⼤⼩,STACKSIZE 定义.def⽂件语法:STACKSIZE reserve[,commit]reserve:栈的⼤⼩;commit:可选项,与操作系统有关,在NT上只⼀次分配物理内存的⼤⼩⽅法⼆:设定/STACK打开⼯程,依次操作菜单如下:Project->链接器->系统,注意:reserve默认值为1MB,最⼩值为4Byte,如修改为4MB,则将reserve改为0x400000;commit是保留在虚拟内存的页⽂件⾥⾯,它设置的较⼤会使栈开辟较⼤的值,可能增加内存的开销和启动时间MSDN中的介绍:/STACK 选项设置堆栈的⼤⼩(以字节为单位)。
此选项仅在⽣成 .exe ⽂件时使⽤。
reserve 值指定虚拟内存中的总的堆栈分配。
对于 x86 和 x64 计算机,默认堆栈⼤⼩为 1 MB。
在 Itanium 芯⽚组上,默认⼤⼩为 4 MB。
commit 取决于操作系统所作的解释。
在 Windows NT 和 Windows 2000 中,它指定⼀次分配的物理内存量。
提交的虚拟内存导致空间被保留在页⾯⽂件中。
更⾼的 commit 值在应⽤程序需要更多堆栈空间时可节省时间,但会增加内存需求并有可能延长启动时间。
对于 x86和 x64 计算机,默认提交值为 4 KB。
在 Itanium 芯⽚组上,默认值为 16 KB。
c#实现内存映射文件共享内存
c#实现内存映射⽂件共享内存内存映射⽂件是利⽤虚拟内存把⽂件映射到进程的地址空间中去,在此之后进程操作⽂件,就像操作进程空间⾥的地址⼀样了,⽐如使⽤c语⾔的 memcpy等内存操作的函数。
这种⽅法能够很好的应⽤在需要频繁处理⼀个⽂件或者是⼀个⼤⽂件的场合,这种⽅式处理IO效率⽐普通IO效率要⾼共享内存是内存映射⽂件的⼀种特殊情况,内存映射的是⼀块内存,⽽⾮磁盘上的⽂件。
共享内存的主语是进程(Process),操作系统默认会给每⼀个进程分配⼀个内存空间,每⼀个进程只允许访问操作系统分配给它的哪⼀段内存,⽽不能访问其他进程的。
⽽有时候需要在不同进程之间访问同⼀段内存,怎么办呢?操作系统给出了创建访问共享内存的API,需要共享内存的进程可以通过这⼀组定义好的API来访问多个进程之间共有的内存,各个进程访问这⼀段内存就像访问⼀个硬盘上的⽂件⼀样。
⽽.Net 4.0中引⼊了System.IO. MemoryMappedFiles命名空间,这个命名空间的类对windows 共享内存相关API做了封装,使.Net程序员可以更⽅便的使⽤内存映射⽂件。
在C#中使⽤共享内存。
以下App1的代码让⽤户输⼊⼀⾏⽂本到共享内存中;App2不停的刷新控制台,输出最新的共享内存内容;App3实现的功能和App2相同,但读取⽅法不同。
00001.App1代码:using System;using System.Collections.Generic;android从资源⽂件中读取⽂件流显⽰using System.Linq;using System.Text;using System.IO;//引⽤内存映射⽂件命名空间using System.IO.MemoryMappedFiles;namespace App1{class Program{static void Main(string[] args){long capacity = 1<<10<<10;//创建或者打开共享内存using (var mmf = MemoryMappedFile.CreateOrOpen("testMmf", capacity, MemoryMappedFileAccess.ReadWrite)){//通过MemoryMappedFile的CreateViewAccssor⽅法获得共享内存的访问器var viewAccessor = mmf.CreateViewAccessor(0, capacity);//循环写⼊,使在这个进程中可以向共享内存中写⼊不同的字符串值while (true){Console.WriteLine("请输⼊⼀⾏要写⼊共享内存的⽂字:");string input = Console.ReadLine();//向共享内存开始位置写⼊字符串的长度viewAccessor.Write(0, input.Length);//向共享内存4位置写⼊字符viewAccessor.WriteArray<char>(4, input.ToArray(), 0, input.Length);}}}}}App2代码:using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;//引⽤使⽤内存映射⽂件需要的命名空间using System.IO.MemoryMappedFiles;namespace App2{class Program{static void Main(string[] args){long capacity = 1<<10<<10;using (var mmf = MemoryMappedFile.OpenExisting("testMmf")){MemoryMappedViewAccessor viewAccessor = mmf.CreateViewAccessor(0, capacity);//循环刷新共享内存字符串的值while (true){//读取字符长度int strLength = viewAccessor.ReadInt32(0);char[] charsInMMf = new char[strLength];//读取字符viewAccessor.ReadArray<char>(4, charsInMMf, 0, strLength);Console.Clear();Console.Write(charsInMMf);Console.Write("\r");Thread.Sleep(200);}}}}}App3代码:using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.IO.MemoryMappedFiles;using System.IO;namespace App3{class Program{static void Main(string[] args){long capacity = 1 << 10 << 10;//打开共享内存using (var mmf = MemoryMappedFile.OpenExisting("testMmf")){//使⽤CreateViewStream⽅法返回stream实例using (var mmViewStream = mmf.CreateViewStream(0, capacity)){//这⾥要制定Unicode编码否则会出问题using (BinaryReader rdr = new BinaryReader(mmViewStream,Encoding.Unicode)){while (true){mmViewStream.Seek(0, SeekOrigin.Begin);int length = rdr.ReadInt32();char[] chars = rdr.ReadChars(length);Console.Write(chars);Console.Write("\r");System.Threading.Thread.Sleep(200);Console.Clear();}}}}}}}00001.在读数据时⽤了2种⽅法。
内存映射的方式
内存映射的方式内存映射是一种将文件或其他设备映射到程序的内存空间的方式,使得程序可以直接读取或写入内存中的数据,而无需通过繁琐的文件读写操作。
常见的内存映射方式有以下几种:1.文件映射:文件映射是将一个文件的内容映射到内存中,使得程序可以直接访问文件的内容。
文件映射可以分为读映射和写映射两种方式。
读映射意味着程序可以直接从内存中读取文件的内容,而无需通过文件读取操作;写映射则允许程序直接将数据写入到内存中,而无需通过文件写入操作。
文件映射可以提高文件的读写性能,减少了文件操作的开销。
2.共享内存映射:共享内存映射是一种特殊的内存映射方式,它允许多个进程之间共享同一段内存空间。
这种方式可以通过建立映射关系,使得多个进程可以直接读写映射到内存中的数据,实现数据共享和通信。
共享内存映射可以提高进程间通信的效率,避免了复制数据的开销。
3.设备映射:设备映射是将设备的寄存器或者是设备对应的内存空间映射到程序的内存空间中,使得程序可以直接操作设备。
这种方式可以提高对设备的访问效率,并且简化了对设备的操作流程。
提高读写性能:因为内存映射可以减少文件读写操作的次数,直接在内存中进行读写操作,因此可以提高读写性能,特别是对于大文件的读写。
简化操作流程:通过内存映射,程序可以直接访问内存中的数据,而无需通过繁琐的文件读写操作或者设备操作,减少了操作的复杂性和开销。
实现数据共享和通信:共享内存映射可以实现不同进程之间的数据共享和通信,提高了进程间通信的效率。
内存限制:程序的内存空间是有限的,如果映射的文件或设备太大,可能会导致内存不足的问题。
并发访问:如果多个进程或线程同时访问同一段内存映射空间,可能会发生竞争条件和数据一致性问题,需要进行相应的同步和互斥处理。
安全性:内存映射方式对于系统的安全性也有一定的影响,需要特别注意对映射区域的保护和权限控制,防止恶意访问和篡改。
总的来说,内存映射是一种高效简便的数据访问方式,可以提高读写性能,简化操作流程,并实现数据共享和通信。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
通过VC++内存映射修改大文件方法本文介绍利用VC++内存映射文件修改大文件的方法:在大文件内存前加入一段数据,若要使用内存映射文件,必须执行下列操作步骤:1.创建或打开一个文件内核对象,该对象用于标识磁盘上你想用作内存映射文件的文件;2.创建一个文件映射内核对象,告诉系统该文件的大小和你打算如何访问该文件;3.让系统将文件映射对象的全部或一部分映射到你的进程地址空间中;当完成对内存映射文件的使用时,必须执行下面这些步骤将它清除:1.告诉系统从你的进程的地址空间中撤消文件映射内核对象的映像;2.关闭文件映射内核对象;3.关闭文件内核对象;下面将用一个实例详细介绍这些操作步骤,(本实例的目的就是将一个文件A其内容前面加入一些内容存入文件B,我想大家在程序开发当中会遇到这种情况的)。
一、我们打开关于A文件内核对象,并创建一个关于B文件的内核对象若要创建或打开一个文件内核对象,总是要调用CreateFile函数:HANDLE CreateFile(PCSTR pszFileName,DWORD dwDesiredAccess,DWORD dwShareMode,PSECURITY_ATTRIBUTES psa,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile);CreateFile函数拥有好几个参数,这里只重点介绍前3个参数,即szFileName,dwDesiredAccess 和dwShareMode。
你可能会猜到,第一个参数pszFileName用于指明要创建或打开的文件的名字(包括一个选项路径),第二个参数dwDesiredAccess用于设定如何访问该文件的内容,可以设定下表所列的4个值中的一个。
当创建或打开一个文件,将它作为一个内存映射文件来使用时,请选定最有意义的一个或多个访问标志,以说明你打算如何访问文件的数据,对内存映射文件来说,必须打开用于只读访问或读写访问的文件,因此,可以分别设定GENERIC_READ或GENERIC_READ|GENERIC_WRITE, 第三个参数dwShareMode 告诉系统你想如何共享该文件,可以为dwShareMode设定下表所列的4个值之一:如果CreateFile函数成功地创建或打开指定的文件,便返回一个文件内核对象的句柄,否则返回INVALID_HANDLE_VALUE, 注意能够返回句柄的大多数Windows函数如果运行失败,那么就会返回NULL,但是,CreateFile函数将返回INVALID_HANDLE_VALUE,它定义为((HANDLE)-1),HANDLEhFile=CreateFile(".\\first.txt",GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTI NG,FILE_FLAG_SEQUENTIAL_SCAN,NULL);HANDLEhmyfile=CreateFile("E:\\my.txt",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL );二、我们要分别创建两个文件映射内核对象调用CreateFile函数,就可以将文件映像的物理存储器的位置告诉操作系统,你传递的路径名用于指明支持文件映像的物理存储器在磁盘(或网络或光盘)上的确切位置,这时,必须告诉系统,文件映射对象需要多少物理存储器,若要进行这项操作,可以调用CreateFileMapping函数:HANDLE CreateFileMapping(HANDLE hFile,PSECURITY_ATTRIBUTES psa,DWORD fdwProtect,DWORD dwMaximumSizeHigh,DWORD dwMaximumSizeLow,PCTSTR pszName);第一个参数hFile用于标识你想要映射到进程地址空间中的文件句柄,该句柄由前面调用的CreateFile函数返回,psa参数是指向文件映射内核对象的SECURITY_ATTRIBUTES结构的指针,通常传递的值是NULL(它提供默认的安全特性,返回的句柄是不能继承的)。
本章开头讲过,创建内存映射文件就像保留一个地址空间区域然后将物理存储器提交给该区域一样,因为内存映射文件的物理存储器来自磁盘上的一个文件,而不是来自从系统的页文件中分配的空间,当创建一个文件映射对象时,系统并不为它保留地址空间区域,也不将文件的存储器映射到该区域(下一节将介绍如何进行这项操作),但是,当系统将存储器映射到进程的地址空间中去时,系统必须知道应该将什么保护属性赋予物理存储器的页面,CreateFileMapping函数的fdwProtect参数使你能够设定这些保护属性,大多数情况下,可以设定下表中列出的3个保护属性之一。
使用fdwProtect参数设定的部分保护属性在Windows98下,可以将PAGE_WRITECOPY标志传递给CreateFileMapping,这将告诉系统从页文件中提交存储器,该页文件存储器是为数据文件的数据拷贝保留的,只有修改过的页面才被写入页文件,你对该文件的数据所作的任何修改都不会重新填入原始数据文件,其最终结果是,PAGE_WRITECOPY标志的作用在Windows2000和Windows98上是相同的。
除了上面的页面保护属性外,还有4个节保护属性,你可以用OR将它们连接起来放入CreateFileMapping函数的fdwProtect参数中,节只是用于内存映射的另一个术语。
节的第一个保护属性是SEC_NOCACHE,它告诉系统,没有将文件的任何内存映射页面放入高速缓存,因此,当将数据写入该文件时,系统将更加经常地更新磁盘上的文件数据,这个标志与PAGE_NOCACHE保护属性标志一样,是供设备驱动程序开发人员使用的,应用程序通常不使用,Windows98将忽略SEC_NOCACHE标志。
节的第二个保护属性是SEC_IMAGE,它告诉系统,你映射的文件是个可移植的可执行(PE)文件映像,当系统将该文件映射到你的进程的地址空间中时,系统要查看文件的内容,以确定将哪些保护属性赋予文件映像的各个页面,例如,PE文件的代码节(.text)通常用PAGE_EXECUTE_READ属性进行映射,而PE文件的数据节(.data)则通常用PAGE_READWRITE 属性进行映射,如果设定的属性是SEC_IMAGE,则告诉系统进行文件映像的映射,并设置相应的页面保护属性。
Windows98将忽略SEC_IMAGE标志最后两个保护属性是SEC_RESERVE和SEC_COMMIT,它们是两个互斥属性,当使用内存映射数据文件时,它们不能使用,这两个标志将在本章后面介绍,当创建内存映射数据文件时,不应该设定这些标志中的任何一个标志,CreateFileMapping将忽略这些标志。
CreateFileMapping的另外两个参数是dwMaximumSizeHigh和dwMaximumSizeLow,它们是两个最重要的参数,CreateFileMapping函数的主要作用是保证文件映射对象能够得到足够的物理存储器,这两个参数将告诉系统该文件的最大字节数,它需要两个32位的值,因为Windows支持的文件大小可以用64位的值来表示,dwMaximumSizeHigh参数用于设定较高的32位,而dwMaximumSizeLow参数则用于设定较低的32位值,对于4GB或小于4GB的文件来说,dwMaximumSizeHigh的值将始终是0。
使用64位的值,意味着Windows能够处理最大为16EB(1018字节)的文件,如果想要创建一个文件映射对象,使它能够反映文件当前的大小,那么可以为上面两个参数传递0,如果只打算读取该文件或者访问文件而不改变它的大小,那么为这两个参数传递0,如果打算将数据附加给该文件,可以选择最大的文件大小,以便为你留出一些富裕的空间,如果当前磁盘上的文件包含0字节,那么可以给CreateFileMapping函数的dwMaximumSizeHigh和dwMaximumSizeLow 传递两个0,这样做就可以告诉系统,你要的文件映射对象里面的存储器为0字节,这是个错误,CreateFileMapping将返回NULL。
如果你对我们讲述的内容一直非常关注,你一定认为这里存在严重的问题,Windows支持最大为16EB的文件和文件映射对象,这当然很好,但是,怎样将这样大的文件映射到32位进程的地址空间(32位地址空间是4GB文件的上限)中去呢,下一节介绍解决这个问题的办法,当然,64位进程拥有16EB的地址空间,因此可以进行更大的文件的映射操作,但是,如果文件是个超大规模的文件,仍然会遇到类似的问题。
若要真正理解CreateFile和CreateFileMapping两个函数是如何运行的,建议你做一个下面的实验,建立下面的代码,对它进行编译,然后在一个调试程序中运行它,当你一步步执行每个语句时,你会跳到一个命令解释程序,并执行C:\目录上的“dir”命令,当执行调试程序中的每个语句时,请注意目录中出现的变化。
int WINAPI _tWinMain(HINSTANCE hinstExe, HINSTANCE,PTSTR pszCmdLine, int nCmdShow){//Before executing the line below, C:\ does not have//a file called "MMFTest.Dat."HANDLE hfile = CreateFile("C:\\MMFTest.dat",GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL, NULL);//Before executing the line below, the MMFTest.Dat//file does exist but has a file size of 0 bytes.HANDLE hfilemap = CreateFileMapping(hfile, NULL, PAGE_READWRITE,0, 100, NULL);//After executing the line above, the MMFTest.Dat//file has a size of 100 bytes.//CleanupCloseHandle(hfilemap);CloseHandle(hfile);//When the process terminates, MMFTest.Dat remains//on the disk with a size of 100 bytes.return(0);}如果调用CreateFileMapping函数,传递PAGE_READWRITE标志,那么系统将设法确保磁盘上的相关数据文件的大小至少与dwMaximumSizeHigh和dwMaximumSizeLow参数中设定的大小相同,如果该文件小于设定的大小,CreateFileMapping函数将扩展该文件的大小,使磁盘上的文件变大,这种扩展是必要的,这样,当以后将该文件作为内存映射文件使用时,物理存储器就已经存在了,如果正在用PAGE_READONLY或PAGE_WRITECOPY标志创建该文件映射对象,那么CreateFileMapping特定的文件大小不得大于磁盘文件的物理大小,这是因为你无法将任何数据附加给该文件。