C语言-内存映射(大文件处理)(创建文件映射内核对象然后在映射到内存地址空间中,当作无类型指针使用)

C语言-内存映射是什么,根据自己粗浅的学习理解,总结为—— 创建一个文件映射内核对象然,然后在把文件映射内核对象映射到内存地址空间中,然后我们拿这个内存地址(也就是无类型类型指针)对内存空间(也就相当与硬盘上的文件)进行操作了。

这里面包含了三大内容(内村指针就不介绍了):文件打开或创建、文件映射内核对象,映射文件映射到内存地址空间

1、文件打开或创建 CreateFile

CreateFile 函数用于创建或打开文件、pipes、邮槽 、通信资源、磁盘驱动器(仅适用于 windowsNT )、控制台 、文件夹(仅用于打开)对象,并返回一个可以用来访问这些对象的句柄。在这里我们只用打开或创建文件。

函数原型:HANDLE CreateFile(
                                                    LPCTSTR lpFileName,                 // 指向文件名的指针 
                                                    DWORD dwDesiredAccess,         // 访问模式(写 / 读) 
                                                    DWORD dwShareMode,               // 共享模式 
                                                    LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 指向安全属性的指针 
                                                    DWORD dwCreationDisposition,   // 如何创建 
                                                    DWORD dwFlagsAndAttributes,    // 文件属性 
                                                    HANDLE hTemplateFile                 // 用于复制文件句柄 
                                                   );

样例:

#include<stdio.h>
#include<Windows.h>
int main(){
    //创建文件
    HANDLE hFile = CreateFile((LPCSTR)FileName,  //文件目录包含文件名
                           GENERIC_WRITE | GENERIC_READ,       //访问模式为读写方式
                           FILE_SHARE_READ | FILE_SHARE_WRITE, //共享模式读写方式
                           NULL,             //句柄不可继承
                           OPEN_ALWAYS,      //如果文件存在,打开则,不覆盖.如果不存在 则创建.
                           FILE_FLAG_SEQUENTIAL_SCAN,  //针对连续访问对文件缓冲进行优化.
                           NULL    //);
	if (hFile == INVALID_HANDLE_VALUE) {
		printf("1-创建文件失败,错误代码:%d ", GetLastError());
	}
    CloseHandle(hFile);        //关闭文件
    system("pause");
    return 0;
}

2、文件映射内核对象 CreateFileMapping

内核对象是系统提供的用户模式下代码与内核模式下代码进行交互的基本接口。

作为一个软件开发人员,你经常需要创建、打开和操作各种内核对象。系统要创建和操作若干类型的内核对象,比如存取符号对象、事件对象、文件对象、文件映射对象、I/O完成端口对象、作业对象、信箱对象、互斥对象、管道对象、进程对象、信标对象、线程对象和等待计时器对象等。这些对象都是通过调用函数来创建的。

CreateFileMapping 函数用于创建一个文件映射内核对象。

函数原型:HANDLE CreateFileMapping(
                                                   HANDLE hFile,                                            //物理文件句柄
                                                   LPSECURITY_ATTRIBUTES lpAttributes,  //安全设置
                                                   DWORD flProtect,                                        //保护设置
                                                   DWORD dwMaximumSizeHigh,                  //高位文件大小
                                                   DWORD dwMaximumSizeLow,                   //低位文件大小
                                                   LPCTSTR lpName                                       //共享内存名称
                                                   );

样例:

#include<stdio.h>
#include<Windows.h>
int main(){
    //创建文件
    HANDLE hFile = CreateFile((LPCSTR)FileName,  //文件目录包含文件名
                           GENERIC_WRITE | GENERIC_READ,       //访问模式为读写方式
                           FILE_SHARE_READ | FILE_SHARE_WRITE, //共享模式读写方式
                           NULL,             //句柄不可继承
                           OPEN_ALWAYS,      //如果文件存在,打开则,不覆盖.如果不存在 则创建.
                           FILE_FLAG_SEQUENTIAL_SCAN,  //针对连续访问对文件缓冲进行优化.
                           NULL    //);
	if (hFile == INVALID_HANDLE_VALUE) {
		printf("1-创建文件失败,错误代码:%d ", GetLastError());
	}
####################################本节案例代码####################################
    //创建文件映射对象
    HANDLE hFileMap = CreateFileMapping(hFile,       //文件句柄(CreateFile返回的文件句柄)
                                    NULL,            //默认的安全配置
                                    PAGE_READWRITE,  //容许读和写
                                    NULL,            //大于4G时有用
                                    NULL,            //文件大小(新建文件时不能为0,会报10016错误)
                                    nullptr          //互斥句柄);
	if (hFileMap == NULL)
	{
		printf("2-创建文件映射内核对象失败,错误代码:%d ", GetLastError());
	}
########################################结束########################################
    CloseHandle(hFile);        //关闭文件
    CloseHandle(hFileMap);     //关闭文件映射
    system("pause");
    return 0;
}

3、映射文件映射到内存地址空间 MapViewOfFile

内存地址空间我也没理解附上几个链接再次:内存地址与内存空间:https://www.cnblogs.com/Lanht/p/10780364.html内存地址空间:https://www.cnblogs.com/lazyli/p/10923909.html

MapViewOfFile 函数是将一个文件映射对象映射到当前应用程序的地址空间

函数原型:HANDLE CreateFileMapping(
                                             __in HANDLE hFileMappingObject,        //文件映像对象句柄
                                             __in DWORD dwDesiredAccess,            //映射对象的文件数据的访问方式
                                             __in DWORD dwFileOffsetHigh,             //文件映射起始偏移的高32位
                                             __in DWORD dwFileOffsetLow,              //文件映射起始偏移的低32位
                                             __in SIZE_T dwNumberOfBytesToMap   //指定映射文件的字节数           
);

#include<stdio.h>
#include<Windows.h>
int main(){
    //创建文件
    HANDLE hFile = CreateFile((LPCSTR)FileName,  //文件目录包含文件名
                           GENERIC_WRITE | GENERIC_READ,       //访问模式为读写方式
                           FILE_SHARE_READ | FILE_SHARE_WRITE, //共享模式读写方式
                           NULL,             //句柄不可继承
                           OPEN_ALWAYS,      //如果文件存在,打开则,不覆盖.如果不存在 则创建.
                           FILE_FLAG_SEQUENTIAL_SCAN,  //针对连续访问对文件缓冲进行优化.
                           NULL    //);
	if (hFile == INVALID_HANDLE_VALUE) {
		printf("1-创建文件失败,错误代码:%d ", GetLastError());
	}

    //创建文件映射对象
    HANDLE hFileMap = CreateFileMapping(hFile,       //文件句柄(CreateFile返回的文件句柄)
                                    NULL,            //默认的安全配置
                                    PAGE_READWRITE,  //容许读和写
                                    NULL,            //大于4G时有用
                                    NULL,            //文件大小(新建文件时不能为0,会报10016错误)
                                    nullptr          //互斥句柄);
	if (hFileMap == NULL)
	{
		printf("2-创建文件映射内核对象失败,错误代码:%d ", GetLastError());
	}
    CloseHandle(hFile);        //关闭文件
####################################本节案例代码####################################
    // 文件映射内核对象映射到当前应用程序的地址空间
	LPVOID lpbMapAddress = MapViewOfFile(hFileMap,     //文件映像对象句柄
                              FILE_MAP_ALL_ACCESS,    //读和写
                              0,                      //大于4G指针偏移量
                              0,                      //小于4G指针偏移量
                              0                       //文件大小(不能大于文件映射对象的大小,否则报错,网上没有找的书可以用0,但我这里写0可以正常使用。
                          );
	if (lpbMapAddress == NULL)
	{
		printf("3-映射文件映射内核对象失败,错误代码:%d ", GetLastError());
		CloseHandle(hFileMap);
		return 0;
	}
    CloseHandle(hFileMap);     //关闭文件映射
########################################结束########################################
    system("pause");
    return 0;
}

到此位置我们的文件就映射到 我类型的lpbMapAddress 指针上了内存大小为我们创建的CreateFileMapping时填的大小,可以像普通无类型指针一样 操作了。

创建或打开的文件句柄在创建完文件映射对象句柄后就可以关闭了,文件映射对象句柄在创建完内存映射后也可以关闭,但有时后期还要用到它,最好不要关闭,到程序结束时再关闭。句柄何时关闭,刚接触是也是很迷糊,经过测试得出了结论。所以在这再唠叨几句。记得最后还要关闭内存映射UnMapViewOfFile(lpbMapAddress )。

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C语言,可以使用pthread库来实现多线程操作,并使用mmap函数来实现内存映射文件。 下面给出一个简单的例子,展示如何使用多线程读取内存映射文件: ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <sys/mman.h> #include <fcntl.h> #include <unistd.h> #define FILE_SIZE (1024*1024*1024*10LL) // 10GB #define THREAD_NUM 4 void *read_file(void *arg); int main() { int fd = open("test.txt", O_RDONLY); if (fd == -1) { perror("open failed"); exit(EXIT_FAILURE); } // 映射文件内存 char *mmap_ptr = mmap(NULL, FILE_SIZE, PROT_READ, MAP_PRIVATE, fd, 0); if (mmap_ptr == MAP_FAILED) { perror("mmap failed"); exit(EXIT_FAILURE); } // 创建多个线程读取文件 pthread_t threads[THREAD_NUM]; for (int i = 0; i < THREAD_NUM; i++) { int *arg = malloc(sizeof(int)); *arg = i; pthread_create(&threads[i], NULL, read_file, arg); } // 等待所有线程结束 for (int i = 0; i < THREAD_NUM; i++) { pthread_join(threads[i], NULL); } // 解除内存映射 munmap(mmap_ptr, FILE_SIZE); return 0; } void *read_file(void *arg) { int id = *(int *)arg; free(arg); long long chunk_size = FILE_SIZE / THREAD_NUM; long long offset = id * chunk_size; char *mmap_ptr = mmap(NULL, chunk_size, PROT_READ, MAP_PRIVATE | MAP_POPULATE, fd, offset); if (mmap_ptr == MAP_FAILED) { perror("mmap failed"); pthread_exit(NULL); } // 读取文件 for (long long i = 0; i < chunk_size; i++) { char c = mmap_ptr[i]; // TODO: process data } // 解除内存映射 munmap(mmap_ptr, chunk_size); pthread_exit(NULL); } ``` 在该例子,首先将文件test.txt映射内存,然后创建多个线程分别读取不同的文件块。每个线程读取自己的文件块时,使用mmap函数将该文件映射内存,并进行读取操作。最后,在所有线程读取完毕后,解除内存映射。 需要注意的是,在使用mmap函数映射文件时,应该考虑到文件大小的限制,避免一次性映射过大的文件导致内存不足。同时,在进行多线程操作时,还应该注意线程同步和互斥问题,避免数据竞争和死锁等问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值