《unix高级环境编程》高级 I/O—— 存储映射 I/O
2014-11-25 16:39
232 查看
存储映射 I/O 使一个磁盘文件与存储空间中的一个缓冲区相映射。于是从缓冲区中取数据,就相当于读文件的相应字节,同理,将数据写入缓冲区,则相应字节就会自动写入文件。这样可以不使用 read 和 write 函数的情况下执行 I/O。
将一个给定的文件映射到缓冲区可以使用 mmap 函数;
[cpp] view
plaincopy
/* 存储映射IO */
/*
* 函数功能:将一个给定文件映射到存储区域中;
* 返回值:若成功则返回缓冲区的起始地址,若出错则返回MAP_FAILED;
* 函数原型:
*/
#include <sys/mman.h>
void *mmap(void *addr, size_t len, int prot, int flag, int filedes, off_t off);
/*
* 说明:
* addr参数用于指定映射存储区的起始地址,通常将其设置为0,这样由系统自动分配起始地址;
* filedes指定要被映射文件的描述符,在映射之前,先要打开该文件;
* len是映射的字节数;
* off是要映射字节在文件中的起始偏移量;
* prot是对映射存储区的保护要求,具体参数是以下的按位"或"组合:
* PROT_READ 映射区可读
* PROT_WRITE 映射区可写
* PROT_EXEC 映射区可执行
* PROT_NONE 映射区不可访问
*
* flag参数影响映射存储区的多重属性:
* MAP_FIXED 返回值必须等于addr;
* MAP_SHARED 说明本进程对映射区所进行的存储操作的配置;指定存储操作修改映射文件;
* MAP_PRIVATE 对映射区的存储操作导致创建该映射文件的一个私有副本,所有后来对映射区的引用都是该副本;
*/
存储映射文件的存储空间如下图所示:
调用 mprotect 可以更改一个现有映射存储区的权限:
[cpp] view
plaincopy
/*
* 函数功能:更改一个现有映射存储区的权限;
* 返回值:若成功则返回0,若出错则返回-1;
* 函数原型:
*/
#include <sys/mman.h>
int mprotect(void *addr, size_t len, int prot);
/*
* 说明:
* 参数prot和mmap函数的参数一样;
* 起始地址addr必须是系统页长的整数倍;
*/
如果在共享存储映射区中的页已被修改,那么我们可以调用 msync 将该页冲洗到被映射的文件中:
[cpp] view
plaincopy
/*
* 函数功能:将页冲洗到被映射的文件中;
* 返回值:若成功则返回0,若出错则返回-1;
* 函数原型:
*/
#include <sys/mman.h>
int msync(void *addr, size_t len, int flags);
/*
* 说明:
* 若映射是私有的,则不修改被映射的文件,地址必须与页边界对齐;
* 参数flags取值如下:
* MS_ASYNC 执行异步写
* MS_SYNC 执行同步写
* MS_INVALIDATE 使高速缓存的数据失效
*/
当我们使用 mmap 函数成功映射存储区之后,我们可以关闭文件描述符 filedes,此操作并不会解除映射区,想要解除映射区必须调用 munmap 函数:
[cpp] view
plaincopy
/*
* 函数功能:解除映射存储区;
* 返回值:若成功则返回0,若出错则返回-1;
* 函数原型:
*/
#include <sys/mman.h>
int munmap(void *addr, size_t len);
munmap 不会影响被映射的对象,也就是说,调用 munmap 不会使映射区的内容写到磁盘文件上。对于 MAP_SHARED 区磁盘文件的更新,在写到存储映射区时按内核虚拟内存算法自动进行,在解除了映射后,对于 MAP_PRIVATE 存储区的修改被丢弃。
测试程序:
[cpp] view
plaincopy
#include "apue.h"
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int fd;
void *dst;
struct stat f_stat;
char buf[MAXLINE];
memset(buf, 0, MAXLINE);
char *src = "mmap munmap msync 12";
if(argc != 2)
err_quit("usage: a.out <pathname>");
if((fd = open(argv[1], O_RDWR)) < 0)
err_sys("open argv[1] file error");
if(fstat(fd, &f_stat) == -1 )
err_sys("fstat error");
if((dst = mmap(NULL, f_stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED)
err_sys("mmap error");
close(fd);
memcpy(dst, src, 20);
if((msync(dst, f_stat.st_size, MS_SYNC)) == -1)
err_sys("msync error");
if((munmap(dst, f_stat.st_size)) == -1)
err_sys("munmap error");
exit(0);
}
原始文件mmap.txt 里面的内容为:
[cpp] view
plaincopy
cat mmap.txt
cccccccccccccccccc
ffffffffffffffffff
eeeeeeeeeeeeeeeeee
yyyyyyyyyyyyyyyyyy
qqqqqqqqqqqqqqqqqq
aaaaaaaaaaaaaaaaaa
pppppppppppppppppp
vvvvvvvvvvvvvvvvvv
zzzzzzzzzzzzzzzzzz
xxxxxxxxxxxxxxxxxx
映射存储之后的内容为:
[cpp] view
plaincopy
mmap munmap msync 12
fffffffffffffffff
eeeeeeeeeeeeeeeeee
yyyyyyyyyyyyyyyyyy
qqqqqqqqqqqqqqqqqq
aaaaaaaaaaaaaaaaaa
pppppppppppppppppp
vvvvvvvvvvvvvvvvvv
zzzzzzzzzzzzzzzzzz
xxxxxxxxxxxxxxxxxx
输出结果:注意:以下是mmap以共享模式的即MAP_SHARED,若是以私有模式的并不会修改源文件
[cpp] view
plaincopy
$cat mmap.txt
cccccccccccccccccc
ffffffffffffffffff
eeeeeeeeeeeeeeeeee
yyyyyyyyyyyyyyyyyy
qqqqqqqqqqqqqqqqqq
aaaaaaaaaaaaaaaaaa
pppppppppppppppppp
vvvvvvvvvvvvvvvvvv
zzzzzzzzzzzzzzzzzz
xxxxxxxxxxxxxxxxxx
$ ./mmap mmap.txt
$ cat mmap.txt
mmap munmap msync 12
fffffffffffffffff
eeeeeeeeeeeeeeeeee
yyyyyyyyyyyyyyyyyy
qqqqqqqqqqqqqqqqqq
aaaaaaaaaaaaaaaaaa
pppppppppppppppppp
vvvvvvvvvvvvvvvvvv
zzzzzzzzzzzzzzzzzz
xxxxxxxxxxxxxxxxxx
将一个给定的文件映射到缓冲区可以使用 mmap 函数;
[cpp] view
plaincopy
/* 存储映射IO */
/*
* 函数功能:将一个给定文件映射到存储区域中;
* 返回值:若成功则返回缓冲区的起始地址,若出错则返回MAP_FAILED;
* 函数原型:
*/
#include <sys/mman.h>
void *mmap(void *addr, size_t len, int prot, int flag, int filedes, off_t off);
/*
* 说明:
* addr参数用于指定映射存储区的起始地址,通常将其设置为0,这样由系统自动分配起始地址;
* filedes指定要被映射文件的描述符,在映射之前,先要打开该文件;
* len是映射的字节数;
* off是要映射字节在文件中的起始偏移量;
* prot是对映射存储区的保护要求,具体参数是以下的按位"或"组合:
* PROT_READ 映射区可读
* PROT_WRITE 映射区可写
* PROT_EXEC 映射区可执行
* PROT_NONE 映射区不可访问
*
* flag参数影响映射存储区的多重属性:
* MAP_FIXED 返回值必须等于addr;
* MAP_SHARED 说明本进程对映射区所进行的存储操作的配置;指定存储操作修改映射文件;
* MAP_PRIVATE 对映射区的存储操作导致创建该映射文件的一个私有副本,所有后来对映射区的引用都是该副本;
*/
存储映射文件的存储空间如下图所示:
调用 mprotect 可以更改一个现有映射存储区的权限:
[cpp] view
plaincopy
/*
* 函数功能:更改一个现有映射存储区的权限;
* 返回值:若成功则返回0,若出错则返回-1;
* 函数原型:
*/
#include <sys/mman.h>
int mprotect(void *addr, size_t len, int prot);
/*
* 说明:
* 参数prot和mmap函数的参数一样;
* 起始地址addr必须是系统页长的整数倍;
*/
如果在共享存储映射区中的页已被修改,那么我们可以调用 msync 将该页冲洗到被映射的文件中:
[cpp] view
plaincopy
/*
* 函数功能:将页冲洗到被映射的文件中;
* 返回值:若成功则返回0,若出错则返回-1;
* 函数原型:
*/
#include <sys/mman.h>
int msync(void *addr, size_t len, int flags);
/*
* 说明:
* 若映射是私有的,则不修改被映射的文件,地址必须与页边界对齐;
* 参数flags取值如下:
* MS_ASYNC 执行异步写
* MS_SYNC 执行同步写
* MS_INVALIDATE 使高速缓存的数据失效
*/
当我们使用 mmap 函数成功映射存储区之后,我们可以关闭文件描述符 filedes,此操作并不会解除映射区,想要解除映射区必须调用 munmap 函数:
[cpp] view
plaincopy
/*
* 函数功能:解除映射存储区;
* 返回值:若成功则返回0,若出错则返回-1;
* 函数原型:
*/
#include <sys/mman.h>
int munmap(void *addr, size_t len);
munmap 不会影响被映射的对象,也就是说,调用 munmap 不会使映射区的内容写到磁盘文件上。对于 MAP_SHARED 区磁盘文件的更新,在写到存储映射区时按内核虚拟内存算法自动进行,在解除了映射后,对于 MAP_PRIVATE 存储区的修改被丢弃。
测试程序:
[cpp] view
plaincopy
#include "apue.h"
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int fd;
void *dst;
struct stat f_stat;
char buf[MAXLINE];
memset(buf, 0, MAXLINE);
char *src = "mmap munmap msync 12";
if(argc != 2)
err_quit("usage: a.out <pathname>");
if((fd = open(argv[1], O_RDWR)) < 0)
err_sys("open argv[1] file error");
if(fstat(fd, &f_stat) == -1 )
err_sys("fstat error");
if((dst = mmap(NULL, f_stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED)
err_sys("mmap error");
close(fd);
memcpy(dst, src, 20);
if((msync(dst, f_stat.st_size, MS_SYNC)) == -1)
err_sys("msync error");
if((munmap(dst, f_stat.st_size)) == -1)
err_sys("munmap error");
exit(0);
}
原始文件mmap.txt 里面的内容为:
[cpp] view
plaincopy
cat mmap.txt
cccccccccccccccccc
ffffffffffffffffff
eeeeeeeeeeeeeeeeee
yyyyyyyyyyyyyyyyyy
qqqqqqqqqqqqqqqqqq
aaaaaaaaaaaaaaaaaa
pppppppppppppppppp
vvvvvvvvvvvvvvvvvv
zzzzzzzzzzzzzzzzzz
xxxxxxxxxxxxxxxxxx
映射存储之后的内容为:
[cpp] view
plaincopy
mmap munmap msync 12
fffffffffffffffff
eeeeeeeeeeeeeeeeee
yyyyyyyyyyyyyyyyyy
qqqqqqqqqqqqqqqqqq
aaaaaaaaaaaaaaaaaa
pppppppppppppppppp
vvvvvvvvvvvvvvvvvv
zzzzzzzzzzzzzzzzzz
xxxxxxxxxxxxxxxxxx
输出结果:注意:以下是mmap以共享模式的即MAP_SHARED,若是以私有模式的并不会修改源文件
[cpp] view
plaincopy
$cat mmap.txt
cccccccccccccccccc
ffffffffffffffffff
eeeeeeeeeeeeeeeeee
yyyyyyyyyyyyyyyyyy
qqqqqqqqqqqqqqqqqq
aaaaaaaaaaaaaaaaaa
pppppppppppppppppp
vvvvvvvvvvvvvvvvvv
zzzzzzzzzzzzzzzzzz
xxxxxxxxxxxxxxxxxx
$ ./mmap mmap.txt
$ cat mmap.txt
mmap munmap msync 12
fffffffffffffffff
eeeeeeeeeeeeeeeeee
yyyyyyyyyyyyyyyyyy
qqqqqqqqqqqqqqqqqq
aaaaaaaaaaaaaaaaaa
pppppppppppppppppp
vvvvvvvvvvvvvvvvvv
zzzzzzzzzzzzzzzzzz
xxxxxxxxxxxxxxxxxx
相关文章推荐
- 《unix高级环境编程》高级 I/O—— 存储映射 I/O
- 高级I/O之存储映射I/O
- 文件高级---IO处理,文件锁,存储映射
- 第3章 文件I/O(7)_高级文件操作:存储映射
- unix高级环境编程(第12章高级终端)
- MyBatis学习笔记(3)—— XML映射文件の结果集(Result Maps)高级结果映射中的构造方法与关联
- MyBatis之使用resultMap实现高级映射
- 利用Azure高级存储搭建高性能Linux服务器(2)
- 《Entity Framework 6 Recipes》中文翻译系列 (35) ------ 第六章 继承与建模高级应用之TPH继承映射中使用复合条件
- Mybatis 高级结果映射 ResultMap Association Collection
- iOS开发UI高级—12ios应用数据存储方式(偏好设置)
- MyBatis 入门到精通(三) 高级结果映射 .
- APUE读书笔记-14高级输入输出-09内存映射IO
- 【Map】——Map用于存储具有映射关系的数据
- JAVA高级【4.6】《Java核心技术2》数据库-存储过程
- MyBatis-高级映射:多对多
- Mybatis高级映射结果集---xml配置---(一对多,多对一)
- Mybatis 高级结果映射 ResultMap Association Collection
- 【MyBatis框架】高级映射-一对一查询
- IIs 网站应用程序与虚拟目录的区别及高级应用说明(文件分布式存储方案)