文档库 最新最全的文档下载
当前位置:文档库 › 通过VC++内存映射修改大文件方法

通过VC++内存映射修改大文件方法

通过VC++内存映射修改大文件方法
通过VC++内存映射修改大文件方法

通过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.

//Cleanup

CloseHandle(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特定的文件大小不得大于磁盘文件的物理大小,这是因为你无法将任何

数据附加给该文件。

CreateFileMapping函数的最后一个参数是pszName,它是个以0结尾的字符串,用于给该

文件映射对象赋予一个名字,该名字用于与其他进程共享文件映射对象(本章后面展示了它的

一个例子,第3章详细介绍了内核对象的共享操作),内存映射数据文件通常并不需要被共享,因

此这个参数通常是NULL。

系统创建文件映射对象,并将用于标识该对象的句柄返回该调用线程,如果系统无法创建

文件映射对象,便返回一个NULL句柄值,记住,当CreateFile运行失败时,它将返回

INVALID_HANDLE_VALUE(定义为-1),当CreateFileMapping运行失败时,它返回NULL,请不要

混淆这些错误值。

在本实例中创建文件映射内核对象代码如下:

HANDLE hFileMapping = CreateFileMapping(hFile, NULL,

PAGE_READONLY, 0, 0, NULL);

DWORD dwFileSizeHigh;

__int64 qwFileSize = GetFileSize(hFile, &dwFileSizeHigh);

qwFileSize += (((__int64) dwFileSizeHigh) << 32);

char AddMsg[]="Girl,you love me?, I love you very much!"; //加入的文件内容

__int64 myFilesize=qwFileSize+sinf.dwAllocationGranularity; //合并后的文件大小

HANDLE hmyfilemap = CreateFileMapping(hmyfile, NULL,

PAGE_READWRITE, //合并文件大小的内存映射对象

(DWORD)(myFilesize>>32), (DWORD)(myFilesize& 0xFFFFFFFF),

NULL);

三、将文件数据映射到地址空间

当创建了一个文件映射对象后,仍然必须让系统为文件的数据保留一个地址空间区域,并

将文件的数据作为映射到该区域的物理存储器进行提交,可以通过调用MapViewOfFile函数来

进行这项操作:

PVOID MapViewOfFile(

HANDLE hFileMappingObject,

DWORD dwDesiredAccess,

DWORD dwFileOffsetHigh,

DWORD dwFileOffsetLow,

SIZE_T dwNumberOfBytesToMap);

参数hFileMappingObject用于标识文件映射对象的句柄,该句柄是前面调用

CreateFileMapping或OpenFileMapping(本章后面介绍)函数返回的,参数dwDesiredAccess用

于标识如何访问该数据,不错,必须再次设定如何访问文件的数据,可以设定下表所列的4个值

中的一个。

表17-6值及其含义

Windows要求所有这些保护属性一次又一次地重复设置,这当然有些奇怪和烦人,我认为

这样做可以使应用程序更多地对数据保护属性进行控制,

剩下的3个参数与保留地址空间区域及将物理存储器映射到该区域有关,当你将一个文件映射到你的进程的地址空间中时,你不必一次性地映射整个文件,相反,可以只将文件的一小部

分映射到地址空间,被映射到进程的地址空间的这部分文件称为一个视图,这可以说明MapViewOfFile是如何而得名的,

当将一个文件视图映射到进程的地址空间中时,必须规定两件事情,首先,必须告诉系统,数据文件中的哪个字节应该作为视图中的第一个字节来映射,你可以使用dwFileOffsetHigh和dwFileOffsetLow参数来进行这项操作,由于Windows支持的文件最大可达16EB,因此必须用一个64位的值来设定这个字节的位移值,这个64位值中,较高的32位传递给参数dwFileOffsetHigh,较低的32位传递给参数dwFileOffsetLow,注意,文件中的这个位移值必须是系统的分配粒度的倍数(迄今为止,Windows的所有实现代码的分配粒度均为64KB),第14章介绍了如何获取某个系统的分配粒度。

第二,必须告诉系统,数据文件有多少字节要映射到地址空间,这与设定要保留多大的地址空间区域的情况是相同的,可以使用dwNumberOfBytesToMap参数来设定这个值,如果设定的值是0,那么系统将设法把从文件中的指定位移开始到整个文件的结尾的视图映射到地址空间。

在Windows98中,如果MapViewOfFile无法找到足够大的区域来存放整个文件映射对象,那么无论需要的视图是多大,MapViewOfFile均将返回NULL。

在Windows2000中,MapViewOfFile只需要为必要的视图找到足够大的一个区域,而不管

整个文件映射对象是多大。

如果在调用MapViewOfFile函数时设定了FILE_MAP_COPY标志,系统就会从系统的页文件中提交物理存储器,提交的地址空间数量由dwNumberOfBytesToMap参数决定,只要你不进行其他操作,只是从文件的映像视图中读取数据,那么系统将决不会使用页文件中的这些提交

的页面,但是,如果进程中的任何线程将数据写入文件的映像视图中的任何内存地址,那么系统

将从页文件中抓取已提交页面中的一个页面,将原始数据页面拷贝到该页交换文件中,然后将

该拷贝的页面映射到你的进程的地址空间,从这时起,你的进程中的线程就要访问数据的本地

拷贝,不能读取或修改原始数据。

当系统制作原始页面的拷贝时,系统将把页面的保护属性从PAGE_WRITECOPY改为

PAGE_READWRITE,下面这个代码段就说明了这个情况:

// Open the file that we want to map.

HANDLE hFile = CreateFile(pszFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL,

OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

// Create a file-mapping object for the file.

HANDLE hFileMapping = CreateFileMapping(hFile, NULL, PAGE_WRITECOPY, 0, 0, NULL);

// Map a copy-on-write view of the file; the system will commit

// enough physical storage from the paging file to accommodate

// the entire file. All pages in the view will initially have

// PAGE_WRITECOPY access.

PBYTE pbFile = (PBYTE) MapViewOfFile(hFileMapping, FILE_MAP_COPY, 0, 0, 0);

// Read a byte from the mapped view.

BYTE bSomeByte = pbFile[0];

// When reading, the system does not touch the committed pages in // the paging file. The page keeps its PAGE_WRITECOPY attribute.

// Write a byte to the mapped view.

pbFile[0] = 0;

// When writing for the first time, the system grabs a committed // page from the paging file, copies the original contents of the // page at the accessed memory address, and maps the new page

// (the copy) into the process's address space. The new page has // an attribute of PAGE_READWRITE.

// Write another byte to the mapped view.

pbFile[1] = 0;

// Because this byte is now in a PAGE_READWRITE page, the system // simply writes the byte to the page (backed by the paging file).

// When finished using the file's mapped view, unmap it.

// UnmapViewOfFile is discussed in the next section. UnmapViewOfFile(pbFile);

// The system decommits the physical storage from the paging file. // Any writes to the pages are lost.

// Clean up after ourselves.

CloseHandle(hFileMapping);

CloseHandle(hFile);

Windows98前面讲过,Windows98必须预先为内存映射文件提交页文件中的存储器,然而,它只有在必要时才将修改后的页面写入页文件,

四、从进程的地址空间撤消文件数据的映射

当不再需要保留映射到你的进程地址空间区域中的文件数据时,可以通过调用下面的函数将它释放:

BOOLUnmapViewOfFile(PVOIDpvBaseAddress);

该函数的唯一的参数pvBaseAddress用于设定返回区域的基地址,该值必须与调用MapViewOfFile函数返回的值相同,必须记住要调用UnmapViewOfFile函数,如果没有调用这个函数,那么在你的进程终止运行前,保留的区域就不会被释放,每当你调用MapViewOfFile时,系统总是在你的进程地址空间中保留一个新区域,而以前保留的所有区域将不被释放。

为了提高速度,系统将文件的数据页面进行高速缓存,并且在对文件的映射视图进行操作

时不立即更新文件的磁盘映像,如果需要确保你的更新被写入磁盘,可以强制系统将修改过的

数据的一部分或全部重新写入磁盘映像中,方法是调用FlushViewOfFile函数: BOOLFlushViewOfFile(

PVOIDpvAddress,

SIZE_TdwNumberOfBytesToFlush);

第一个参数是包含在内存映射文件中的视图的一个字节的地址,该函数将你在这里传递的地址圆整为一个页面边界值,第二个参数用于指明你想要刷新的字节数,系统将把这个数字向上圆整,使得字节总数是页面的整数,如果你调用FlushViewOfFile函数并且不修改任何数据,那么该函数只是返回,而不将任何信息写入磁盘。

对于存储器是在网络上的内存映射文件来说,FlushViewOfFile能够保证文件的数据已经从工作站写入存储器,但是FlushViewOfFile不能保证正在共享文件的服务器已经将数据写入远程磁盘,因为服务器也许对文件的数据进行了高速缓存,若要保证服务器写入文件的数据,每当你为文件创建一个文件映射对象并且映射该文件映射对象的视图时,应该将

FILE_FLAG_WRITE_THROUGH标志传递给CreateFile函数,如果你使用该标志打开该文件,那么只有当文件的全部数据已经存放在服务器的磁盘驱动器中的时候,FlushViewOfFile函数才返回。

记住UnmapViewOfFile函数的一个特殊的特性,如果原先使用FILE_MAP_COPY标志来映射视图,那么你对文件的数据所作的任何修改,实际上是对存放在系统的页文件中的文件数据的拷贝所作的修改,在这种情况下,如果调用UnmapViewOfFile函数,该函数在磁盘文件上就没有什么可以更新,而只会释放页文件中的页面,从而导致数据丢失。

如果想保留修改后的数据,必须采用别的措施,例如,你可以用同一个文件创建另一个文件映射对象(使用PAGE_READWRITE),然后使用FILE_MAP_WRITE标志将这个新文件映射对象映射到进程的地址空间,之后,你可以扫描第一个视图,寻找带有PAGE_READWRITE保护属性的页面,每当你找到一个带有该属性的页面时,可以查看它的内容,并且确定是否将修改了的数据写入该文件,如果不想用新数据更新该文件,那么继续对视图中的剩余页面进行扫描,直到视图的结尾,但是,如果你确实想要保存修改了的数据页面,那么只需要调用MoveMemory函数,将数据页面从第一个视图拷贝到第二个视图,由于第二个视图是用PAGE_READWRITE保护属性映射的,因此MoveMemory函数将更新磁盘上的实际文件内容,可以使用这种方法来确定文件的变更并保存你的文件的数据。

Windows98不支持copy-on-write(写入时拷贝)保护属性,因此,当扫描内存映射文件的第一个视图时,无法测试用PAGE_READWRITE标志做上标记的页面,你必须设计一种方法来确定第一个视图中的哪些页面已经做了修改。

五、关闭文件映射对象和文件对象

不用说,你总是要关闭你打开了的内核对象,如果忘记关闭,在你的进程继续运行时会出现资源泄漏的问题,当然,当你的进程终止运行时,系统会自动关闭你的进程已经打开但是忘记关闭的任何对象,但是如果你的进程暂时没有终止运行,你将会积累许多资源句柄,因此你始终都

应该编写清楚而又“正确的”代码,以便关闭你已经打开的任何对象,若要关闭文件映射对象和文件对象,只需要两次调用CloseHandle函数,每个句柄调用一次:

让我们更加仔细地观察一下这个进程,下面的伪代码显示了一个内存映射文件的例子:

HANDLEhFile=CreateFile(...);

HANDLEhFileMapping=CreateFileMapping(hFile,...);

PVOIDpvFile=MapViewOfFile(hFileMapping,...);

//Usethememory-mappedfile.

UnmapViewOfFile(pvFile);

CloseHandle(hFileMapping);

CloseHandle(hFile);

上面的代码显示了对内存映射文件进行操作所用的“预期”方法,但是,它没有显示,当你调用MapViewOfFile时系统对文件对象和文件映射对象的使用计数的递增情况,这个副作用是很大的,因为它意味着我们可以将上面的代码段重新编写成下面的样子:

HANDLEhFile=CreateFile(...);

HANDLEhFileMapping=CreateFileMapping(hFile,...);

CloseHandle(hFile);

PVOIDpvFile=MapViewOfFile(hFileMapping,...);

CloseHandle(hFileMapping);

//Usethememory-mappedfile.

UnmapViewOfFile(pvFile);

当对内存映射文件进行操作时,通常要打开文件,创建文件映射对象,然后使用文件映射对象将文件的数据视图映射到进程的地址空间,由于系统递增了文件对象和文件映射对象的内部使用计数,因此可以在你的代码开始运行时关闭这些对象,以消除资源泄漏的可能性,

如果用同一个文件来创建更多的文件映射对象,或者映射同一个文件映射对象的多个视图,那么就不能较早地调用CloseHandle函数——以后你可能还需要使用它们的句柄,以便分别对CreateFileMapping和MapViewOfFile函数进行更多的调用,

本实例中第三到第六步代码如下:

CloseHandle(hFile);//Wenolongerneedaccesstothefileobject'shandle. CloseHandle(hmyfile);

PBYTEpbmyFile=(PBYTE)MapViewOfFile(hmyfilemap,FILE_MAP_WRITE,//内

存映射视图

0,//Startingbyte

0,//infile

sizeof(AddMsg));

memcpy(pbmyFile,AddMsg,sizeof(AddMsg));//加入内容

UnmapViewOfFile(pbmyFile);

__int64qwFileOffset=0;//A文件视图的偏移量

__int64qwmyFileOffset=sinf.dwAllocationGranularity;//合并文件视图

的遍移量

while(qwFileSize>0)

{

//Determinethenumberofbytestobemappedinthisview DWORDdwBytesInBlock=sinf.dwAllocationGranularity;

if(qwFileSize

PBYTEpbFile=(PBYTE)MapViewOfFile(hFileMapping,FILE_MAP_READ, (DWORD)(qwFileOffset>>32),//Startingbyte

(DWORD)(qwFileOffset&0xFFFFFFFF),//infile

dwBytesInBlock);//#ofbytestomap

PBYTEpbmyFile=(PBYTE)MapViewOfFile(hmyfilemap,FILE_MAP_WRITE, (DWORD)(qwmyFileOffset>>32),//Startingbyte

(DWORD)(qwmyFileOffset&0xFFFFFFFF),//infile

dwBytesInBlock);

memcpy(pbmyFile,pbFile,dwBytesInBlock);

//Unmaptheview;wedon'twantmultipleviews

//inouraddressspace.

UnmapViewOfFile(pbFile);

UnmapViewOfFile(pbmyFile);

//Skiptothenextsetofbytesinthefile.

qwmyFileOffset+=dwBytesInBlock;

qwFileOffset+=dwBytesInBlock;

qwFileSize-=dwBytesInBlock;

}

CloseHandle(hFileMapping);

CloseHandle(hmyfilemap);

参考资料:《Windows核心编程》

Richter是一位让人佩服的前辈,本文99%是引用前辈原文,原创部份甚少,请各位莫见笑(本人纯属初学者),者作深厚的技术功底与精湛的语言,让我对内存映射文件操作有了清晰的认识,若大家有什么不清楚之处,可以联系我,小弟愿与你们探讨,

关于VB内存映射文件的使用

VB内存映射文件的使用 引言 文件操作是应用程序最为基本的功能之一,Win32 API和MFC均提供有支持文件处理的函数和类,常用的有Win32 API的CreateFile()、WriteFile()、ReadFile()和MFC提供的CFile类等。一般来说,以上这些函数可以满足大多数场合的要求,但是对于某些特殊应用领域所需要的动辄几十GB、几百GB、乃至几TB的海量存储,再以通常的文件处理方法进行处理显然是行不通的。目前,对于上述这种大文件的操作一般是以内存映射文件的方式来加以处理的,本文下面将针对这种Windows核心编程技术展开讨论。 内存映射文件 内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,同时将物理存储器提交给此区域,只是内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而非系统的页文件,而且在对该文件进行操作之前必须首先对文件进行映射,就如同将整个文件从磁盘加载到内存。由此可以看出,使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行I/O操作,这意味着在对文件进行处理时将不必再为文件申请并分配缓存,所有的文件缓存操作均由系统直接管理,由于取消了将文件数据加载到内存、数据从内存到文件的回写以及释放内存块等步骤,使得内存映射文件在处理大数据量的文件时能起到相当重要的作用。另外,实际工程中的系统往往需要在多个进程之间共享数据,如果数据量小,处理方法是灵活多变的,如果共享数据容量巨大,那么就需要借助于内存映射文件来进行。实际上,内存映射文件正是解决本地多个进程间数据共享的最有效方法。 内存映射文件并不是简单的文件I/O操作,实际用到了Windows的核心编程技术--内存管理。所以,如果想对内存映射文件有更深刻的认识,必须对Windows操作系统的内存管理机制有清楚的认识,内存管理的相关知识非常复杂,超出了本文的讨论范畴,在此就不再赘述,感兴趣的读者可以参阅其他相关书籍。 内存映射文件使用方法 1) 首先要通过CreateFile()函数来创建或打开一个文件内核对象,这个对象标识了磁盘上将要用作内 存映射文件的文件。 2)在用CreateFile()将文件映像在物理存储器的位置通告给操作系统后,只指定了映像文件的路径, 映像的长度还没有指定。为了指定文件映射对象需要多大的物理存储空间还需要通过 CreateFileMapping()函数来创建一个文件映射内核对象以告诉系统文件的尺寸以及访问文件的方式。 3)在创建了文件映射对象后,还必须为文件数据保留一个地址空间区域,并把文件数据作为映射到该 区域的物理存储器进行提交。由MapViewOfFile()函数负责通过系统的管理而将文件映射对象的全部或部分映射到进程地址空间。此时,对内存映射文件的使用和处理同通常加载到内存中的文件数据的处理方式基本一样。 4)在完成了对内存映射文件的使用时,还要通过一系列的操作完成对其的清除和使用过资源的释放。 这部分相对比较简单,可以通过UnmapViewOfFile()完成从进程的地址空间撤消文件数据的映像、通过CloseHandle()关闭前面创建的文件映射对象和文件对象。 内存映射文件相关函数 在使用内存映射文件时,所使用的API函数主要就是前面提到过的那几个函数,下面分别对其进行介绍:

手柄映射键盘工具JoyToKey使用教程

joytokey教程使用方法2009-01-14 20:33joytokey教程使用方法手柄映射键盘工具JoyToKey使用教程1 JoyToKey是通过手柄或操纵杆来模拟键盘、鼠标的软件,它可以将手柄输入模拟成键、鼠输入传到系统中,完成不支持手 柄或操纵杆的操作。更为难得的是,该软件支持几乎所有的游戏手柄,连低端的仿PS的并口手柄也不例例外。目前还有 很多电脑游戏不支持手柄,这给电视游戏玩家和喜欢用手柄的电脑游戏玩家操纵游戏带来了不小的麻烦,不少玩家心中会 恨恨地想:“如果这款游戏支持手柄,我早就爆机N次了!”其实,一切都可以用JoyToKey 来解决。下面以《仙剑奇侠传 》DOS版为例来介绍一下使用办法:首先下载JoyToKey汉化版,这是一个免安装软件,运行进入程序主界面,点击“新建 ”按钮,为《仙剑奇侠传》程序建立一个配置文件,文件可以取名为“仙剑奇侠传”。 了解《仙剑奇侠传》需要用到的键盘上的按键:“上下左右”为“↑↓→←”,“ESC”和空格键为功能键。(另 :有些游戏可以修改键盘设置,如果用到JoyToKey就不用按照自己的习惯来个性化设置,默认就可以,但是手柄与键盘的 对应关系必须搞清楚,可以按照自己的意愿来对应。)接下来我们便可以根据前面提到的按键进行手柄模拟设置了。 例如,要将手柄方向键向左的按键模拟为键盘的左箭头“←”,只需在JoyToKey主界面右侧的按钮列表中双击“←”标记 在弹出的“设置功能”对话框中选择“键盘”选项卡,将鼠标定位在“键盘模拟输入”栏下的第一个空白输入框中,并在 键盘上按一下左箭头“←”,在该输入框内则会出现一个向左的箭头符号(见图)。单击“确定”按钮后便完成了对该按 键的设置。按照同样的方法,我们可以将键盘上的方向键和其他功能按键都模拟成为手柄上的相应按钮。如果需要用到鼠

计算机内存发展史

计算机内存发展史 内存是电脑必不可少的组成部分,CPU 可通过数据总线对内存寻址。历史上的电脑 主板上有主内存,内存条是主内存的扩展。 以后的电脑主板上没有主内存,CPU完全依 赖内存条。所有外存上的内容必须通过内存 才能发挥作用。 在计算机诞生初期并不存在内存条的概 念,最早的内存是以磁芯的形式排列在线路 上,每个磁芯与晶体管组成的一个双稳态电路作为一比特(BIT)的存储器,每一比特都要有玉米粒大小,可以想象一间的机房只能装下不超过百k字节左右的容量。后来才出线现了焊接在主板上集成内存芯片,以内存芯片的形式为计算机的运算提供直接支持。那时的内存芯片容量都特别小,最常见的莫过于 256K×1bit、1M×4bit,虽然如此,但这相对于那时的运算任务来说却已经绰绰有余了。一、内存条的诞生 内存芯片的状态一直沿用到286初期,鉴于它存 在着无法拆卸更换的弊病,这对于计算机的发展造成 了现实的阻碍。有鉴于此,内存条便应运而生了。将 内存芯片焊接到事先设计好的印刷线路板上,而电脑 主板上也改用内存插槽。这样就把内存难以安装和更 换的问题彻底解决了。 在80286主板发布之前,内存并没有被世人所重 视,这个时候的内存是直接固化在主板上,而且容量 只有64 ~256KB,对于当时PC所运行的工作程序 来说,这种内存的性能以及容量足以满足当时软件程 序的处理需要。不过随着软件程序和新一代80286硬件平台的出现,程序和硬件对内存性能提出了更高要求,为了提高速度并扩大容量,内存必须以独立的封装形式出现,因而诞生了“内存条”概念。 在80286主板刚推出的时候,内存条采用了SIMM(Single In-lineMemory Modules,单边接触内存模组)接口,容量为30pin、256kb,必须是由8 片数据位和1 片校验位组成1 个bank,正因如此,我们见到的30pin SIMM一般是四条一起使用。自1982年PC进入民用市场一直到现在,搭配80286处理器的30pin SIMM 内存是内存领域的开山鼻祖。 随后,在1988 ~1990 年当中,PC 技术迎来另一个发展高峰,也就是386和486时代,此时CPU 已经向16bit 发展,所以30pin SIMM 内存再也无法满足需求,其较低的内存带宽已经成为急待解决的瓶颈,所以此时72pin SIMM 内存出现了,72pin SIMM支持32bit快速页模式内存,内存带宽得以大幅度提升。72pin SIMM内存单条容量一般为 512KB ~2MB,而且仅要求两条同时使用,由于其与30pin SIMM 内存无法兼容,因此这个时候PC业界毅然将30pin SIMM 内存淘汰出局了。

主板芯片和内存映射

astrotycoon 大道至简,贵在恒久力行

Diagram for modern motherboard. The northbridge and southbridge make up the chipset.

(补充: 北桥芯片用于与CPU、内存和AGP视频接口,这些接口具有很高的传输速率。北桥芯片还起着存储器控制作用,因此Intel把该芯片标号为MCH(Memory Controller Hub)芯片。南桥芯片用来管理低、中速的组件,例如,PCI总线、IDE硬盘接口、USB端口等,因此南桥芯片的名称为ICH(I/O Controller Hub)) As you look at this, the crucial thing to keep in mind is that the CPU doesn’t really know anything about what it’s connected to. It talks to the outside world through its pins bu t it doesn’t care what that outside world is. It might be a motherboard in a computer but it could be a toaster, network router, brain implant, or CPU test bench. There are thre e main ways by which the CPU and the outside communicate: memory address space, I/O address space, and interrupts. We only worry about motherboards and memory for now. 正如你所看到的,其实CPU是完全不知道自己与哪些外部器件相连接的。 CPU仅仅通过自己的引脚与外界沟通,而它并不关心自己是与什么设备在沟通。或许是另一台计算机的主板,或许是烤面包机,网络路由器,脑植入医疗设备,又或许是CPU测试仪。 CPU主要通过三种方式与外界通信:内存地址空间,IO地址空间,和中断。我们目前只关注主板和内存。 In a motherboard the CPU’s gateway to the world is the front-side bus connecting it to the northbridge. Whenever the CPU needs to read or write memory it does so via this b us. It uses some pins to transmit the physical memory address it wants to write or read, while other pins send the value to be written or receive the value being read. An Intel Core 2 QX6600 has 33 pins to transmit the physical memory address (so there are 233 choices of memory locations) and 64 pins to send or receive data (so data is transmitte d in a 64-bit data path, or 8-byte chunks). This allows the CPU to physically address 64 gigabytes of memory (233 locations * 8 bytes) although most chipsets only handle up to 8 gigs of RAM. CPU通过前端总线与北桥芯片连接,作为与外界通信的桥梁。无论何时,CPU都可以通过前端总线来读写内存。 CPU通过一些引脚来传送想要读写物理内存的地址,同时通过另一些引脚来发送将要写入内存的数据或者接收从内存读取到的数据。 Intel Core 2 QX6600 用33个引脚来传送物理内存地址(因此共有233 个内存地址),并且用64个引脚来发送或接收数据(所以数据在64位通道中传输,也就是8字节的数据块)。因此C PU可以访问64G的物理内存(233*8字节),尽管多数芯片组只能处理8G大小的物理内存。 Now comes the rub. We’re used to thinking of memory only in terms of RAM, the stuff programs read from and write to all the time. And indeed most of the memory requests from the processor are routed to RAM modules by the northbridge. But not all of them. Physical memory addresses are also used for communication with assorted devices on t he motherboard (this communication is called memory-mapped I/O). These devices include video cards, most PCI cards (say, a scanner or SCSI card), and also the flash mem ory that stores the BIOS. 那么现在的问题是,通常一提起内存我们仅仅联想到RAM,以为程序一直读写的就只是RAM。的确,绝大多数来自CPU的内存访问请求都被北桥芯片映射到了RAM。但是,注意,不是全部。物理内存同样可以用来与主板上的各种设备通信(这种通信方式被称为I/O内存映射)。这些设备包括显卡,大多数PCI卡(比如,扫描仪,或者是SCSI卡),也包括存储BIOS的flash存储器。 When the northbridge receives a physical memory request it decides where to route it: should it go to RAM? Video card maybe? This routing is decided via the memory addres s map. For each region of physical memory addresses, the memory map knows the device that owns that region. The bulk of the addresses are mapped to RAM, but when the y aren’t the memory map tells the chipset which device should service requests for those addresses. This mapping of memory addresses away from RAM modules causes the c lassic hole in PC memory between 640KB and 1MB. A bigger hole arises when memory addresses are reserved for video cards and PCI devices. This is why 32-bit OSes have pr oblems using 4 gigs of RAM. In Linux the file /proc/iomem neatly lists these address range mappings. The diagram below shows a typical memory map for the first 4 gigs of p hysical memory addresses in an Intel PC:

键盘布局优化

键盘布局优化 我们目前使用的键盘都是QWERTY键盘布局,以键盘第一排字母的左边6个字母而得名。QWERTY键盘在1868年由Christopher Sholes提出,旨在解决打字速度过快导致的某些键组合卡键的问题。因此,打字速度最大化并不是QWERTY键盘的主要目的。QWERTY键盘满足了当时的需求,得到了大范围的推广。 随着技术的发展,键盘早已不存在之前提到的卡键问题。于是,1936年美国人August Dvorak设计出了另外一种键盘,将常用字母都归在一起,以期提高打字速度,这种键盘被称作Dvorak键盘。 对于中文,一般用拼音进行输入。拼音的输入有全拼和双拼两种,全拼就是按照顺序输入汉字的所有拼音,而双拼则直接输入汉字拼音的声母和韵母,以提高打字速度。关于双拼的详细介绍如下: 汉语拼音中绝大部分音由声母和韵母两部分组成,少数如“啊”、“安”、“哦”等只有韵母。而声母和韵母又可以分为单字母的和多字母的——除zh、ch、sh外所有的声母都是单字母,除a、e、i、o、u、v,6个元音外所有的韵母都是多字母的。所以,只要将zh、ch、sh,3个声母用只作韵母的6个元音中的3个表示,而将6元音以外的所有韵母用6元音以外的键来表示,那么所有的音都能用两个键打出来。 有专家提出,对最优的打字速度来说,键盘应该设计成: 1.右手和左手的负荷应该是相等的。 2.最大化中间排(home row)的负荷。 3.两手顺序交替的频率最大化,并且相同手指的频率最小化。 请根据以上信息,建立数学模型,解决以下问题: 1.请设计评价指标,利用附件给出的文本数据,对QWERTY键盘与Dvorak键盘进行 评估。 2.根据附件给出的英文和中文文本数据,统计相关信息,建立数学模型,设计针对英 文和中文全拼的最优键盘布局。 3.根据附件给出的中文文本数据,在QWERTY键盘的基础上,建立模型设计最优双 拼方案,即确定zh、ch、sh声母和除6元音外所有韵母的映射方案。 注: 1.对于键盘的优化设计,不考虑键盘的物理布局设计,仅对字母与键位的映射关系进 行优化设计。 2.上文中给出的专家建议仅供参考,建模时不一定局限于此。 3.对于中文的键盘布局设计,仅考虑用拼音输入中文的情况,不考虑五笔输入。 4.若附件中给出的文本数据不合适或数据量不够大,可自行寻找合适的文本数据。

内存映射文件

内存映射文件: 内存映射文件有三种,第一种是可执行文件的映射,第二种是数据文件的映射,第三种是借助页面交换文件的内存映射.应用程序本身可以使用后两种内存映射. 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()......

内存的发展历程

内存的发展历程 作为PC不可缺少的重要核心部件——内存,它伴随着DIY硬件走过了多年历程。从286时代的30pin SIMM内存、486时代的72pin SIMM 内存,到Pentium时代的EDO DRAM内存、PII 时代的SDRAM内存,到P4时代的DDR内存和目前9X5平台的DDR2内存。内存从规格、技术、总线带宽等不断更新换代。不过我们有理由相信,内存的更新换代可谓万变不离其宗,其目的在于提高内存的带宽,以满足CPU不断攀升的带宽要求、避免成为高速CPU运算的瓶颈。那么,内存在PC领域有着怎样的精彩人生呢?下面让我们一起来了解内存发展的历史吧。 一、历史起源——内存条概念 如果你细心的观察,显存(或缓存)在目前的DIY硬件上都很容易看到,显卡显存、硬盘或光驱的缓存大小直接影响到设备的性能,而寄存器也许是最能代表PC硬件设备离不开RAM 的,的确如此,如果没有内存,那么PC将无法运转,所以内存自然成为DIY用户讨论的重点话题。 在刚刚开始的时候,PC上所使用的内存是一块块的IC,要让它能为PC服务,就必须将其焊接到主板上,但这也给后期维护带来的问题,因为一旦某一块内存IC坏了,就必须焊下来才能更换,由于焊接上去的IC不容易取下来,同时加上用户也不具备焊接知识(焊接需要掌握焊接技术,同时风险性也大),这似乎维修起来太麻烦。 因此,PC设计人员推出了模块化的条装内存,每一条上集成了多块内存IC,同时在主板上也设计相应的内存插槽,这样内存条就方便随意安装与拆卸了(如图1),内存的维修、升级都变得非常简单,这就是内存“条”的来源。 图1,内存条与内存槽的出现 小帖士:内存(Random Access Memory,RAM)的主要功能是暂存数据及指令。我们可以同时写数据到RAM 内存,也可以从RAM 读取数据。由于内存历来都是系统中最大的性能瓶颈之一,因此从某种角度而言,内存技术的改进甚至比CPU 以及其它技术更为令人激动。 二、开山鼻祖——SIMM 内存 在80286主板发布之前,内存并没有被世人所重视,这个时候的内存是直接固化在主板上,而且容量只有64 ~256KB,对于当时PC所运行的工作程序来说,这种内存的性能以及容量足以满足当时软件程序的处理需要。不过随着软件程序和新一代80286硬件平台的出现,程序和硬件对内存性能提出了更高要求,为了提高速度并扩大容量,内存必须以独立的封装形式出现,因而诞生了前面我们所提到的“内存条”概念。

如何禁用某个键或修改键盘映射

How to Disable Caps Lock Key in Windows 7 or Vista Windows 7 或Vista下如何禁用大小写锁定键(同样适用于任意按键间的映射) The caps lock key is one of those remnants of another age of computers, back when people used to shout at each other more often. Unless you’re in the accounting department, it’s probably not very useful, so today we’ll learn how to disable it. 大小写锁定键毫无用处,索性将其禁用。 If you’re using Mac OS X instead, you can follow our guide on how to disable Caps Lock in OS X using a registry hack, or you can map any key to any key if you really want to. 如果你是Mac OS X用户... Note:This article was originally published years ago, but we’ve updated it and are republishing for everybody that might not have seen it. Image by Laurence Vagner 再版说明,略过。 Understanding How Windows Key Re-Mapping Works 了解Windows键盘重映射的工作方式

计算机发展史简介

一、计算机发展史简介 人类所使用的计算工具是随着生产的发展和社会的进步,从简单到复杂、从低级到高级的发展过程,计算工具相继出现了如算盘、计算尺、手摇机械计算机、电动机械计算机等。 1946年,世界上第一台电子数字计算机(ENIAC)在美国诞生。这台计算机共用了18000多个电于管组成,占地170m2,总重量为30t,耗电140kw,运算速度达到每秒能进行5000次加法、 300次乘法。从计算机的发展趁势看,大约2010年前美国就可以研制出千万亿次计算机。 电子计算机在短短的50多年里经过了电子管、晶体管、集成电路(IC)和超大规模集成电路(VLSI)四个阶段的发展,使计算机的体积越来越小,功能越来越强,价格越来越低,应用越来越广泛,目前正朝智能化(第五代)计算机方向发展。1.第一代电子计算机 第一代电于计算机是从1946年至1958年。它们体积较大,运算速度较低,存储容量不大,而且价格昂贵。使用也不方便,为了解决一个问题,所编制的程序的复杂程度难以表述。这一代计算机主要用于科学计算,只在重要部门或科学研究部门使用。 2.第二代电子计算机 第二代计算机是从1958年到1965年,它们全部采用晶体管作为电子器件,其运算速度比第一代计算机的速度提高了近百倍,体积为原来的几十分之一。在软件方面开始使用计算机算法语言。这一代计算机不仅用于科学计算,还用于数据处理和事务处理及工业控制。 3.第三代电子计算机 第三代计算机是从1965年到1970年。这一时期的主要特征是以中、小规模集成电路为电子器件,并且出现操作系统,使计算机的功能越来越强,应用范围越来越广。它们不仅用于科学计算,还用于文字处理、企业管理、自动控制等领域,出现了计算机技术与通信技术相结合的信息管理系统,可用于生产管理、交通管理、情报检索等领域。 4.第四代电子计算机 第四代计算机是指从1970年以后采用大规模集成电路(LSI)和超大规模集成电路(VLSI)为主要电子器件制成的计算机。例如80386微处理器,在面积约为10mm X l0mm的单个芯片上,可以集成大约32万个晶体管。 第四代计算机的另一个重要分支是以大规模、超大规模集成电路为基础发展起来的微处理器和微型计算机。 微型计算机大致经历了四个阶段: 第一阶段是1971~1973年,微处理器有4004、4040、8008。 1971年Intel公司研制出MCS4微型计算机(CPU为4040,四位机)。后来又推出以8008为核心的MCS-8型。 第二阶段是1973~1977年,微型计算机的发展和改进阶段。微处理器有8080、8085、M6800、Z80。初期产品有Intel公司的MCS一80型(CPU为8080,八位机)。后期有TRS-80型(CPU为Z80)和APPLE-II型(CPU为6502),在八十年代初期曾一度风靡世界。 第三阶段是1978~1983年,十六位微型计算机的发展阶段,微处理器有8086、6、80286、M68000、Z8000。微型计算机代表产品是IBM-PC(CPU为8086)。本阶段

设定语言和键盘布局

设定语言和键盘布局 如果希望夏时制时间更改时自动调整计算机时钟,请确认选择了“根据夏时制自 动调节时间”复选框在“控制面板”中打开“区域选项”。在“日期”选项卡上,单 击“用两个数字表示年份时,代表下面时间段的年份”下的箭头以设置终止年份。注 意要打开“控制面板”项,请单击“开始”,指向“设置”单击“控制面板”,然后 双击相应的国标。该特性具有叨年的时间间隔。默认时间段为鲍至删年。用此选项来 解释两位数字年份的程序会在和之间也包括这两年的年份前面加上,在和之间也包括 这两年的年份前面加上。 AVX在“音频”选项卡的“声音播放”中,单击“音量”。在“音量控制”对话框中,在“音量控制”下,向上或向下拖动“音量”滑块以增大 或减小输出音量。注意要打开“控制面板”项,请单击“开始”,指向“设置”,单 击“控制面板”,然后双击相应的图标。在“音频”选项卡上可以限制程序只使用特 定的声卡,方法是在“首选设备”中选定该声卡,然后选定“仅使用首选设备”。 如果选中了“声音”选项卡中的“在任务栏显示音量控制”复选框,并且可以用 软件更改声卡的音量,则将在任务栏上显示扬声器图标。通过单击该图标并拖动滑块 可以调整音量。十、更改计算机的时间和时区在“控制面板”中打开“日期和时间”。在“时间和日期”选项卡下,选择要更改的项目。要更改小时,选择小时,然后单击 箭头增加或减少该值。要更改分钟,选择分钟,然后单击箭头增加或减少该值。要更 改秒,请选择秒,然后单击箭头增加或减少该值。要更改指示器,话选择该指示器, 然后单击箭头。在“时区”选项卡上,地图上方的框中,单击当地的时区。注意要打 开“控制面板”项目,莆单击“TAJD157K016RNJ开始”,指向“设置”,单击“控 制面板”,然后双击相应的团标肥使用时间设置来识别文件的创建和修改时间。例如,“四”被解释为“四”年,而则被解释为“删”。 四位数年份不受此选项影响。并非所有程序都使用该选项。如果正在使用的程序 没有正确解释两位数的年份请咨询该程序的制造商或查阅其文档在“控制面板”中打 开“区域选项”。在“常规”选项卡的“系统的语言设置”下面语言组旁边的复选框。注意必须作为管理员或管理组的成员登录才能完成该步骤。如果计算机与网络连接, 则网络策略设置可能也会阻止您完成此过程。要打开“控制面板”项,请单击“开始”,指向“设置”,单击“控制钽电容面板”,然后双击相应的图标。要完成语言 组安装,必须插入删光盘或从网络访问系统文件。 一旦安装了语言,就提示您重新启动计算机。用安装在计算机上的多种语言,可 以撰写包含多种语言的文档。任何多语种文档的收件人必须在计算机中安装相同的语 言来读取或编辑这些文档十三、添加输入法区域设置和园盘布局在“控制面板”中打 开“区域选项”。在“输入法区域设置”选项卡上,单击“添加”。在“添加输入法

内存映射和普通文件访问的区别

在讲述文件映射的概念时, 不可避免的要牵涉到虚存(SVR 4的VM). 实际上, 文件映射是虚存的中心概念, 文件映射一方面给用户提供了一组措施, 好似用户将文件映射到自己地址空间的某个部分, 使用简单的内存访问指令读写文件;另一方面, 它也可以用于内核的基本组织模式, 在这种模式种, 内核将整个地址空间视为诸如文件之类的一组不同对象的映射. 中的传统文件访问方式是, 首先用open系统调用打开文件, 然后使用read, write以及lseek等调用进行顺序或者随即的I/O. 这种方式是非常低效的, 每一次I/O操作都需要一次系统调用. 另外, 如果若干个进程访问同一个文件, 每个进程都要在自己的地址空间维护一个副本, 浪费了内存空间. 而如果能够通过一定的机制将页面映射到进程的地址空间中, 也就是说首先通过简单的产生某些内存管理数据结构完成映射的创建. 当进程访问页面时产生一个缺页中断, 内核将页面读入内存并且更新页表指向该页面. 而且这种方式非常方便于同一副本的共享. VM是面向对象的方法设计的, 这里的对象是指内存对象: 内存对象是一个软件抽象的概念, 它描述内存区与后备存储之间的映射. 系统可以使用多种类型的后备存储, 比如交换空间, 本地或者远程文件以及帧缓存等等. VM系统对它们统一处理, 采用同一操作集操作, 比如读取页面或者回写页面等. 每种不同的后备存储都可以用不同的方法实现这些操作. 这样, 系统定义了一套统一的接口, 每种后备存储给出自己的实现方法. 这样, 进程的地址空间就被视为一组映射到不同数据对象上的的映射组成. 所有的有效地址就是那些映射到数据对象上的地址. 这些对象为映射它的页面提供了持久性的后备存储. 映射使得用户可以直接寻址这些对象. 值得提出的是, VM体系结构独立于Unix系统, 所有的Unix系统语义, 如正文, 数据及堆栈区都可以建构在基本VM系统之上. 同时, VM体系结构也是独立于存储管理的, 存储管理是由操作系统实施的, 如: 究竟采取什么样的对换和请求调页算法, 究竟是采取分段还是分页机制进行存储管理, 究竟是如何将虚拟地址转换成为物理地址等等(Linux中是一种叫Three Level Page Table的机制), 这些都与内存对象的概念无关. 下面介绍Linux中 VM的实现. 一个进程应该包括一个mm_struct(memory manage struct), 该结构是进程虚拟地址空间的抽象描述, 里面包括了进程虚拟空间的一些管理信息: start_code, end_code, start_data, end_data, start_brk, end_brk等等信息. 另外, 也有一个指向进程虚存区表(vm_area_struct: virtual memory area)的指针, 该链是按照虚拟地址的增长顺序排列的. 在Linux进程的地址空间被分作许多区(vma), 每个区(vma)都对应虚拟地址空间上一段连续的区域, vma是可以被共享和保护的独立实体, 这里的vma就是前面提到的内存对象. 下面是vm_area_struct的结构, 其中, 前半部分是公共的, 与类型无关的一些数据成员, 如: 指向mm_struct的指针, 地址范围等等, 后半部分则是与类型相关的成员, 其中最重要的是一个指向vm_operation_struct向量表的指针 vm_ops, vm_pos向量表是一组虚函数, 定义了与vma类型无关的接口. 每一个特定的子类, 即每种vma类型都必须在向量表中实现这些操作. 这里包括了: open, close, unmap, protect, sync, nopage, wppage, swapout这些操作. 1.struct vm_area_struct { 2./*公共的, 与vma类型无关的 */ 3.struct mm_struct * vm_mm;

几种常用的经常出现于现有嵌入式应用中的内存映射I-O方法概述

几种常用的经常出现于现有嵌入式应用中的内存映射I/O方法概述Linux 暴风雨般占领了嵌入式系统市场。分析家指出,大约有1/3到1/2的32/64位新的嵌入式系统设计采用了Linux。嵌入式Linux 已经在很多应用领域显示出优势,比如SOHO家庭网络和成像/多功能外设。在(NAS/SAN)存储,家庭数字娱乐(HDTV/PVR/DVR /STB),和手持设备/无线设备,特别是数字移动电话更获得大幅度发展。 嵌入式Linux新应用不会凭空从开发者的头脑中冒出来,大部分项目都是由成千上万行,甚至数百万行的代码组成。成千上百的嵌入式项目已经成功地将现有的其它平台的代码移植到Linux下,比如Wind River VxWorks 和pSOS,VRTX,Nucleus 和其它RTOS。这些移植工作有着重要的价值和现实意义。 到目前为止,大多数关于移植已有的RTOS应用到嵌入式Linux的文献,关注RTOS 接口(API)、任务、调度模式以及怎样将他们映射到相应得用户空间去。同样重要的是,在I/O调用密集的嵌入式程序中如何将RTOS的硬件接口代码移植到更加规范的Linux设备驱动程序中去。 本文将概述几种常用的经常出现于现有嵌入式应用中的内存映射I/O方法。它们涵盖的范围从对中断服务例程的特殊使用及用户线程对硬件访问到出现于有些ROTS中的半规范化驱动程序模型。这对于移植RTOS 代码到规范化的Linux设备启动程序具有一定启发作用,并且介绍了一些移植方法。特别地,本文会重点讨论RTOS和Linux中的内存映射,基于I/O 调度队列的移植,将RTOS I/O重定义到Linux下的驱动程序和守护进程里。RTOS I/O 概念 “不规范”是描述大多数RTOS系统I/O的最佳词语。多数RTOS是针对较早的无MMU 的CPU而设计,所以忽略了内存管理部分,即使当MMU问世后也是这样:不区分物理地址和逻辑地址。大多数RTOS还全部运行在特权模式,虽然表面上看来是增强了性能。全部的RTOS 应用和系统代码都能够访问整个地址空间、内存映射过的设备、以及其他I/O操作。这样,即使存在差别,也是很难把RTOS应用程序代码同驱动程序代码区分开

内存映射文件

内存映射文件 内存映射文件是由一个文件到一块内存的映射。Win32提供了允许应用程序把文件映射到一个进程的函数(CreateFileMapping)。这样,文件内的数据就可以用内存读/写指令来访问,而不是用ReadFile和WriteFile这样的I/O系统函数,从而提高了文件存取速度。 这种函数最适用于需要读取文件并且对文件内包含的信息做语法分析的应用程序,如对输入文件进行语法分析的彩色语法编辑器,编译器等。把文件映射后进行读和分析,能让应用程序使用内存操作来操纵文件,而不必在文件里来回地读、写、移动文件指针。 有些操作,如放弃“读”一个字符,在以前是相当复杂的,用户需要处理缓冲区的刷新问题。在引入了映射文件之后,就简单的多了。应用程序要做的只是使指针减少一个值。 映射文件的另一个重要应用就是用来支持永久命名的共享内存。要在两个应用程序之间共享内存,可以在一个应用程序中创建一个文件并映射之,然后另一个应用程序可以通过打开和映射此文件把它作为共享的内存来使用。 VC++中使用内存映射文件处理大文件(1) 关键词:VC++ 内存映射 阅读提示:本文给出了一种方便实用的解决大文件的读取、存储等处理的方法,并结合相关程序代码对具体的实现过程进行了介绍。 引言 文件操作是应用程序最为基本的功能之一,Win32 API和MFC均提供有支持文件处理的函数和类,常用的有Win32 API的CreateFile()、WriteFile()、ReadFile()和MFC 提供的CFile类等。一般来说,以上这些函数可以满足大多数场合的要求,但是对于某些特殊应用领域所需要的动辄几十GB、几百GB、乃至几TB的海量存储,再以通常的文件处理方法进行处理显然是行不通的。目前,对于上述这种大文件的操作一般是以内存映射文件的方式来加以处理的,本文下面将针对这种Windows核心编程技术展开讨论。 内存映射文件 内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,同时将物理存储器提交给此区域,只是内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而非系统的页文件,而且在对该文件进行操作之前必须首先对文件进行映射,就如同将整个文件从磁盘加载到内存。由此可以看出,使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行I/O操作,这意味着在对文件进行处理时将不必再为文件申请并分配缓存,所有的文件缓存操作均由系统直接管理,由于取消了将文件数据加载到内存、数据从内存到文件的回写以及释放内存块等步骤,使得内存映射文件在处理大数据量的文件时能起到相当重要的作用。另外,实际工程中的系统往往需要在多个进程之间共享数据,如果数据量小,处理方法是灵活多变的,如果共享数据容量巨大,那么就需要借助于内存映射文件来进行。实际上,内存映射文件正是解决本地多个进程间数据共享的最有效方法。 内存映射文件并不是简单的文件I/O操作,实际用到了Windows的核心编程技术--内存管理。所以,如果想对内存映射文件有更深刻的认识,必须对Windows操作系统的内存管理机制有清楚的认识,内存管理的相关知识非常复杂,超出了本文的讨论范畴,

计算机内存发展史

计算机内存发展史内部编号:(YUUT-TBBY-MMUT-URRUY-UOOY-DBUYI-0128)

计算机内存发展史 在计算机诞生初期并不存在内存条的概念,最早的内存是以磁芯的形式排列在线路上,每个磁芯与晶体管组成的一个双稳态电路作为一比特(BIT)的存储器,每一比特都要有玉米粒大小,可以想象一间的机房只能装下不超过百k字节左右的容量。后来才出线现了焊接在主板上集成内存芯片,以内存芯片的形式为计算机的运算提供直接支持。那时的内存芯片容量都特别小,最常见的莫过于256K×1bit、1M×4bit,虽然如此,但这相对于那时的运算任务来说却已经绰绰有余了。 内存条的诞生 内存芯片的状态一直沿用到286初期,鉴于它存在着无法拆卸更换的弊病,这对于计算机的发展造成了现实的阻碍。有鉴于此,内存条便应运而生了。将内存芯片焊接到事先设计好的印刷线路板上,而电脑主板上也改用内存插槽。这样就把内存难以安装和更换的问题彻底解决了。 在80286主板发布之前,内存并没有被世人所重视,这个时候的内存是直接固化在主板上,而且容量只有64 ~256KB,对于当时PC所运行的工作程序来说,这种内存的性能以及容量足以满足当时软件程序的处理需要。不过随着软件程序和新一代80286硬件平台的出现,程序和硬件对内存性能提出了更高要求,为了提高速度并扩大容量,内存必须以独立的封装形式出现,因而诞生了“内存条”概念。 在80286主板刚推出的时候,内存条采用了SIMM(Single In-lineMemory Modules,单边接触内存模组)接口,容量为30pin、256kb,必须是由8 片数据位和1 片校验位组成1 个bank,正因如此,我们见到的30pin SIMM一般是四条一起使用。自1982年PC进入民用市场一直到现在,搭配80286处理器的30pin SIMM 内存是内存领域的开山鼻祖。 随后,在1988 ~1990 年当中,PC 技术迎来另一个发展高峰,也就是386和486时代,此时CPU 已经向16bit 发展,所以30pin SIMM 内存再也无法满足需求,其较低的内存带宽已经成为急待解决的瓶颈,所以此时72pin SIMM 内存出

相关文档
相关文档 最新文档