一、内存映射
1.内存映射的概念
把文件的一个区间映射到进程的虚拟地址空间 ,获得一段虚拟地址, 实现文件磁盘地址和这一段虚拟地址的一一对映关系。(即往这段虚拟地址写入数据,就相当于往这个文件中写入数据)
2.内存映射与普通文件IO的区别
例如:想把一些数据写入到文件中。
普通文件IO:
open()访问文件 -> 得到一个文件描述符fd -> 直接往文件描述符fd写入数据就可以了 -> 关闭文件描述符fd。
内存映射:
open()访问文件 -> 得到一个文件描述符fd -> 根据文件描述符fd去内存空间上映射一块空间,得到一个地址p -> 用户只需要将数据拷贝到内存空间上就可以了 -> 对应的文件就会有相应的变化 -> 撤销映射 -> 关闭文件描述符fd。
使用内存映射刷图片的优点:相对普通文件IO虽然代码步骤增加了,但是刷图的速度会更快。
3.内存映射相关函数
-
内存映射函数 mmap的用法
man 2 mmap
头文件:
#include <sys/mman.h>
函数原型:
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
返回值类型:void *
返回值:
成功:返回指向映射空间首地址的指针
失败:MAP_FAILED
形参一:
addr:映射空间首地址,一般设置NULL,让系统决定
形参二:
length:设置映射空间的大小 在这里我们是800 * 480 * 4字节
形参三:
prot:映射空间权限
PROT_READ 可读
PROT_WRITE 可写
常用这两个,如果需要可读可写,只需要将两个或上即可
形参四:
flags:映射空间属性
MAP_SHARED:共享属性 (打开文件方式需要可读可写)
形参五:
fd:想要映射的文件对应文件描述符(先打开文件,才可以映射)
形参六:
offset:被映射文件的映射位置的偏移量(相对于映射空间的首地址),设置0
-
取消映射函数 munmap的用法
头文件:
#include <sys/mman.h>
函数原型:
int munmap(void *addr, size_t length);
返回值类型:int
返回值:
成功:0
失败:-1
形参一:
addr:需要取消的映射空间的首地址
形参二:
length:需要取消的映射空间的大小 在这里我们是800 * 480 * 4字节
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
int main(int argc, char *argv[])
{
// 1、打开fb0、bmp文件
int lcd_fd = open("/dev/fb0", O_RDWR);
if (lcd_fd == -1)
{
printf("open lcd error!\n");
return -1;
}
int bmp_fd = open("./123.bmp", O_RDONLY);
if (bmp_fd == -1)
{
printf("open bmp error!\n");
return -1;
}
// 2、读取bmp文件的数据
char bmp_buf[800*480*3];
lseek(bmp_fd, 54, SEEK_SET); // 跳过bmp文件头和信息头
read(bmp_fd, bmp_buf, 800*480*3); // 读取bmp文件数据到bmp_buf
//3、数据处理
int lcd_buf[800*480];
int x,y;
for (y = 0; y < 480; y++)
{
for (x = 0; x < 800; x++)
{
lcd_buf[800*(479-y)+x] = bmp_buf[3*(800*y+x)] | bmp_buf[3*(800*y+x)+1]<<8 | bmp_buf[3*(800*y+x)+2]<<16;
}
}
//4、内存映射
int *p = (int *)mmap(NULL, 800*480*4, PROT_READ|PROT_WRITE, MAP_SHARED, lcd_fd, 0);
if (p == MAP_FAILED)
{
printf("mmap error!\n");
return -1;
}
// 5、将数据拷贝到映射空间
int n;
for(n=0;n<800*480;n++)
{
*(p+n) = lcd_buf[n];
}
/*
p ---> lcd_buf[0]
p+1 ---> lcd_buf[1]
p+2 ---> lcd_buf[2]
p+n ---> lcd_buf[n]
*/
// 6、关闭fb0、bmp文件、取消映射
munmap(p, 800*480*4);
close(lcd_fd);
close(bmp_fd);
return 0;
}