第3章 文件I/O(7)_高级文件操作:存储映射
8. 高级文件操作:存储映射
(1)概念:
存储映射是一个磁盘文件与存储空间的一个缓存相映射,对缓存数据的读写就相应的完成了文件的读写。
(2)mmap和munmap函数
|
头文件 |
#include<sys/types.h> #include<sys/mman.h> |
|
函数 |
void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset); int munmap(void* addr, size_t length); |
|
返回值 |
mmap成功时返回映射区的起始地址,munmap成功为0,两者出错均返回-1。 |
|
功能 |
mmap:I/O使一个磁盘文件与存储空间中的一个缓存相映射。 Munmap:解除映射。 |
|
参数 |
(1)addr:存储映射区的起始地址,通常设为0,让系统自动分配 (2)length:需要映射的字节数。 (3)prot:保护策略 ①PROT_READ:映射区可读;②PROT_WRITE:映射区可写; ③PROT_EXEC:映射区可执行;④PROT_NONE:映射区不可访问。 (4)flags: ①MAP_FIXED:返回地址必须等于addr,不鼓励使用 ②MAP_SHARED:存储操作立刻修改映射文件内容。 ③MAP_PRIVATE:存储操作导致创建映射文件的副本,并对副本读写。 (5)offset:映射字节在文件中的偏移量 |
|
备注 |
(1)mmap函数从缓存中获取数据,就相当于读文件中相应的字节。与其类似,将数据存入缓存,则相应字节就自动地写入文件。这样,就可以在不使用read和write的情况下执行I/O。 (2)子进程继承父进程的存储映射区。 |
【编程实验】存储映射实现文件写入
//file_map.c
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
int main(int argc, char* argv[])
{
if(argc < 2){
printf("usage: %s file\n",argv[1]);
exit(1);
}
int fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC);
if(fd < 0){
perror("open error");
exit(1);
}
//定位到文件尾部第26个字节的位置,并创建一个空洞文件
lseek(fd, 25, SEEK_END);//定位第26个字母Z,所在的位置
write(fd, "0", 1); //先写入一个"0",以后会被字母Z覆盖
//对文件的“空洞”区进行存储映射
char* addr = mmap(0, //映射区起始地址由系统自动分配
26, //映射的字节数
PROT_WRITE,
MAP_SHARED,
fd,
0); //从指定的文件偏移量处开始映射
//修改存储映射区的内容(会同步到文件中去)
int i = 0;
for(i=0; i<26; i++)
{
*(addr + i) = 'A' + i; //往空洞区写入26个大写字母
}
printf("write success\n");
//解除映射
munmap(addr, 0);
close(fd);
return 0;
}
【编程实验】存储映射实现文件的拷贝
//cp_map.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
int main(int argc, char* argv[])
{
if(argc < 3){
printf("usage: %s srcfile, destfile\n", argv[0]);
exit(1);
}
int srcfd = open(argv[1], O_RDONLY);
if (srcfd < 0)
{
perror("open error");
exit(1);
}
int dstfd = open(argv[2],
O_RDWR | O_CREAT | O_TRUNC, 0777);
if(dstfd < 0 )
{
perror("open error");
exit(1);
}
off_t len = lseek(srcfd, 0, SEEK_END); //源文件的长度
printf("len: %ld\n", len);
//源文件映射到内存
char* addr1 = mmap(0, len, PROT_READ, MAP_SHARED, srcfd, 0);
if(addr1 < 0)
{
perror("mmap error");
exit(1);
}
//在目标文件中,首先创建一个空洞文件
lseek(dstfd, len-1, SEEK_SET);
write(dstfd, "0", 1); //这个0会被后面复制而来的文件内容覆盖
//目标文件映射到内存
char* addr2 = mmap(0, len, PROT_WRITE, MAP_SHARED, dstfd, 0);
if(addr2 < 0)
{
perror("mmap error");
exit(1);
}
//存储映射区的复制,并同步到目标文件中
memcpy(addr2, addr1, len); //拷addr1内容拷到addr2中
printf("copy success!\n");
//撤销映射
munmap(addr1, 0);
munmap(addr2, 0);
close(srcfd);
close(dstfd);
return 0;
}

浙公网安备 33010602011771号