假设我将标准的“Hello, World! \n”保存到名为 hello.txt 的文本文件中。如果我想将“H”更改为“R”或其他内容,我可以使用 mmap() 来实现吗?
mmap标准 C99(或 C11)规范中不存在。它是在 POSIX 中定义的。
因此,假设您有 POSIX 系统(例如 Linux),您可以首先打开(2)文件进行读写:
int myfd = open("hello.txt", O_RDWR);
if (myfd<0) { perror("hello.txt open"); exit(EXIT_FAILURE); };
Run Code Online (Sandbox Code Playgroud)
然后您可以使用fstat(2)获取文件的大小(和其他元数据):
struct stat mystat = {};
if (fstat(myfd,&mystat)) { perror("fstat"); exit(EXIT_FAILURE); };
Run Code Online (Sandbox Code Playgroud)
现在文件的大小为mystat.st_size.
off_t myfsz = mystat.st_size;
Run Code Online (Sandbox Code Playgroud)
现在我们可以调用 mmap(2)并且需要共享映射(以便能够通过虚拟地址空间在文件内写入)
void*ad = mmap(NULL, myfsz, PROT_READ|PROT_WRITE, MAP_SHARED,
myfd, 0);
if (ad == MMAP_FAILED) { perror("mmap"); exit(EXIT_FAILURE); };
Run Code Online (Sandbox Code Playgroud)
然后我们可以覆盖第一个字节(并且我们检查该文件中的第一个字节确实是H 您所承诺的):
assert (*(char*ad) == 'H');
((char*)ad) = 'R';
Run Code Online (Sandbox Code Playgroud)
我们可以调用msync(2)以确保文件立即在磁盘上更新。如果我们不这样做,它可能会稍后更新。
特别是对于非常大的映射(特别是那些比可用 RAM 大得多的映射),我们可以通过madvise(2)或posix_madvise(3)给出的提示来帮助内核(及其页面缓存) ...
请注意,即使在close(2)之后,映射仍然有效。使用munmap&mprotect或mmap与MAP_FIXED在同一地址范围内
在 Linux 上,您可以使用proc(5)来查询地址空间。所以你的程序可以读取(例如 after ,在循环中fopen使用)伪文件(或pid 1234 的进程)。fgets/proc/self/maps/proc/1234/maps
顺便说一句,由dlopen(3)mmap使用;它可以被调用很多次,我的Manydl.c程序演示了在 Linux 上您可以拥有数十万个-ed 共享文件(数十万个内存映射)。dlopen