【Linux編程】存儲映射I/O

存儲映射I/O使一個磁盤文件與存儲空間中的一個緩衝區相映射,對緩衝區的讀、寫操做就是對文件的讀、寫操做,從而可以再也不使用read、write系統調用。

將文件映射到存儲區的函數由mmap完畢,函數原型例如如下:
#include <sys/mman.h>
 
/* 成功返回映射區起始地址,出錯返回MAP_FAILED */
void *mmap(void *addr, size_t len, int prot, int flag, int filedes, off_t off);


參數說明:
  • addr:指定映射存儲區的起始地址,一般爲0表示由系統選擇起始地址。
  • len:需要映射的字節數。
  • prot:對映射存儲區的保護要求,不能超過open文件時的權限。
    • PROT_READ:映射區可讀
    • PROT_WRITE:映射區可寫
    • PROT_EXEC:映射區可運行
    • PROT_NONE:映射區不可訪問
  • flag:影響映射存儲區的屬性。
    • MAP_FIXED:返回值必須等於addr,不利於移植。不鼓舞使用。
    • MAP_SHARED:表示存儲操做至關於對該文件的write。
    • MAP_PRIVATE:對映射區的存儲操做致使建立該映射文件的一個私有副本。
  • filedes:指定要被映射的文件描寫敘述符,映射以前需要先打開該文件。
  • off:要映射字節在文件裏的起始偏移量。一般爲0。

存儲映射例如如下所看到的:


測試代碼:
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
 
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
 
int main(int argc, char *argv[])
{
    int fdin, fdout;
    void *src, *dst;
    struct stat statbuf;
 
    if (argc != 3)
    {
        printf("usage: %s <fromfile> <tofile>\n", argv[0]);
        return -1;
    }
 
    fdin = open(argv[1], O_RDONLY);
    fdout = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, FILE_MODE);
 
    fstat(fdin, &statbuf);
 
    lseek(fdout, statbuf.st_size - 1, SEEK_SET);
    write(fdout, " ", 1);   /* lseek偏移量大於文件長度時。寫操做將加長文件 */
 
    src = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fdin, 0);
    dst = mmap(0, statbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fdout, 0);
 
    memcpy(dst, src, statbuf.st_size);  /* 數據複製 */
 
    munmap(src, statbuf.st_size);
    munmap(dst, statbuf.st_size);
 
    return 0;
}


此函數實現了文件內容之間的拷貝。

lseek + write的組合操做使得目標文件的大小添加到和源文件大小一樣。因爲當lseek設置的文件偏移量大於文件當前長度時。下一個寫操做將會使文件增大。假設沒有對目標文件擴大。那麼進程會接收到SIGBUS信號。表示存儲區中有地址沒法映射到文件裏。編程


mmap其實是將包括文件內容的內核緩衝區映射到應用程序地址空間,而後用memcpy直接進行數據的拷貝。其優點在於避免了相似read、write系統調用,在內核空間和用戶空間之間的數據傳遞。

參考:
《unix環境高級編程》 P390-P395.
相關文章
相關標籤/搜索