mmap, munmap - map or unmap files or devices into memory
SYNOPSIS
#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() creates a new mapping in the virtual address space of the call‐
ing process. The starting address for the new mapping is specified in
addr. The length argument specifies the length of the mapping.
mmap() 创建一个虚拟地址空间的映射。
munmap()删除特定地址范围的映射。
addr : 映射地址,通常为NULL(由系统自动分配);
length : 映射空间大小
prot : 映射空间的权限(可执行、写、读或者无);
flag : 映射空间是否共享等;
fd : 文件描述符;
offset:文件偏移;
1st:通过linux系统调用函数对于文件的操作代码如下所示:
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#define pathname "./text.txt"
int main(int argc, char** argv)
{
int fd = open(pathname, O_RDWR);
if (fd < 0)
{
perror("open");
return 0;
}
char * st = (char *)malloc(5);
fd = read(fd,st,5); //读取text.txt前五个字符hello
if (fd < 0)
{
perror("read");
return 0;
}
printf("%s\n",st);
close(fd);
return 0;
}
xxx@ubuntu:~/CSDN/about_mmp$ gcc mmap.c
xxx@ubuntu:~/CSDN/about_mmp$ ls
a.out mmap.c text.txt
xxx@ubuntu:~/CSDN/about_mmp$ cat text.txt
hello about_mmaphello
xxx@ubuntu:~/CSDN/about_mmp$ ./a.out
hello
同样也可使用mmap映射一块内存对应于text.txt,可通过返回的指针直接对文件继续修改。
在使用mmap之前,mmap第二个参数length : 映射空间大小,即文件text.txt的大小可通过fstat函数获得,可通过man fstat查看函数说明如下:
NAME
stat, fstat, lstat, fstatat - get file status
SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *pathname, struct stat *buf);
//These functions return information about a file, in the buffer pointed to by buf.
//这些函数返回文件的信息,放于由buf指针指向的struct stat结构体中,结构体信息:
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */ **// 该项为我们所需要的文件大小**
blksize_t st_blksize; /* blocksize for filesystem I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
/* Since Linux 2.6, the kernel supports nanosecond
precision for the following timestamp fields.
For the details before Linux 2.6, see NOTES. */
struct timespec st_atim; /* time of last access */
struct timespec st_mtim; /* time of last modification */
struct timespec st_ctim; /* time of last status change */
#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};
2nd:通过mmap函数映射出的空间对文件操作代码如下所示:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#define pathname "./text.txt"
int main(int argc, char * argv[])
{
int fd = open(pathname, O_RDWR); //首先打开文件
if (fd < 0)
{
perror("open_error");
return 0;
}
struct stat stat_; //定义一个struct stat结构体用于存放text.txt文件信息
int ret = fstat(fd, &stat_); //结构体stat_中的stat_.st_size项即为该文件的大小
if (ret < 0)
{
perror("fstat_error");
return 0;
}
//mmap函数映射的虚拟空间对应于text.txt文件的实际物理空间,也即通过修改映射出来的虚拟空间的地址,即可直接修改文件。
char * ret_ = mmap(NULL, stat_.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (ret_ == (void *)-1)
{
perror("mmao_error");
return 0;
}
printf("ret_ = %s\n",ret_);
ret[2] = '*';
printf("ret_ = %s\n",ret_);
munmap(ret_, stat_.st_size); //删除映射
return 0;
xxx@ubuntu:~/CSDN/about_mmp$ ./a.out
ret_ = hello about_mmaphello
ret_ = he*lo about_mmaphello
对比代码1和代码2,两种方式修改文件text.txt,代码1是通过系统调用函数进行修改,代码2是通过地址空间映射方式修改。LINUX下一切皆文件,当需要对某个文件中内容快速修改时,直接修改映射空间的当时明显要优于通过系统调用读写的方式。