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 < ){
printf("usage: %s file\n",argv[]);
exit();
} int fd = open(argv[], O_RDWR | O_CREAT | O_TRUNC);
if(fd < ){
perror("open error");
exit();
} //定位到文件尾部第26个字节的位置,并创建一个空洞文件
lseek(fd, , SEEK_END);//定位第26个字母Z,所在的位置
write(fd, "0", ); //先写入一个"0",以后会被字母Z覆盖 //对文件的“空洞”区进行存储映射
char* addr = mmap(, //映射区起始地址由系统自动分配
, //映射的字节数
PROT_WRITE,
MAP_SHARED,
fd,
); //从指定的文件偏移量处开始映射 //修改存储映射区的内容(会同步到文件中去)
int i = ;
for(i=; i<; i++)
{
*(addr + i) = 'A' + i; //往空洞区写入26个大写字母
} printf("write success\n"); //解除映射
munmap(addr, );
close(fd); return ;
}
【编程实验】存储映射实现文件的拷贝
//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 < ){
printf("usage: %s srcfile, destfile\n", argv[]);
exit();
} int srcfd = open(argv[], O_RDONLY);
if (srcfd < )
{
perror("open error");
exit();
} int dstfd = open(argv[],
O_RDWR | O_CREAT | O_TRUNC, );
if(dstfd < )
{
perror("open error");
exit();
} off_t len = lseek(srcfd, , SEEK_END); //源文件的长度
printf("len: %ld\n", len); //源文件映射到内存
char* addr1 = mmap(, len, PROT_READ, MAP_SHARED, srcfd, );
if(addr1 < )
{
perror("mmap error");
exit();
} //在目标文件中,首先创建一个空洞文件
lseek(dstfd, len-, SEEK_SET);
write(dstfd, "0", ); //这个0会被后面复制而来的文件内容覆盖 //目标文件映射到内存
char* addr2 = mmap(, len, PROT_WRITE, MAP_SHARED, dstfd, );
if(addr2 < )
{
perror("mmap error");
exit();
} //存储映射区的复制,并同步到目标文件中
memcpy(addr2, addr1, len); //拷addr1内容拷到addr2中 printf("copy success!\n"); //撤销映射
munmap(addr1, );
munmap(addr2, ); close(srcfd);
close(dstfd); return ;
}