linux系統IO操作


本文重點說明下面內容:

  • 什么是標准IO,什么是文件IO?
  • 什么是Direct IO? O_SYNC標識有什么意義?
  • 各個層面的緩存如何同步?
  • 還在page cache中的臟頁可以讀寫嗎?

IO路徑上的各層buff

Application buff
|
clib buff
|
page cache
|
disk cache

標准IO

  • 標准IO操作的是流(File對象)
  • 標准IO可以設置緩存,這個緩存是用戶態buffer,一般稱為clib buff
    api
#include <stdio.h>

//打開流
FILE *fopen(const char *pathname, const char *type);

//關閉流
int fclose(File *fp);

// 刷新流
int fflush(FILE *fp);

// 一次讀寫一個字符
int fgetc(FILE *fp);
int fputc(FILE *fp);

// 一次讀寫一行
char* fgets(char* buf, int n, FILE* fp);
int fputs(const char *str, FILE* fp);

// 二進制讀寫
size_t fread(void *ptr, size_t size, size_t nobj, FILE *fp);
size_t fwrite(const void *ptr, size_t size, size_t nobj, FILE *fp);

// 格式化輸入輸出
int fprintf(FILE *fp, const char* format, ...);
int fscanf(FILE *fp, const char *format, ...);

// 示例
#include <stdio.h>
#include <stdlib.h>
int main(void){
    char buf[1024];

    while (fgets(buf, 1024, stdin) != NULL)
        if (fputs(buf, stdout) == EOF)
            printf("output error");

    if (ferror(stdin))
        printf("input error");
    
    exit(0);
}

說明

  • 調用fwrite, fputc, fputs系列函數后,數據被保存到clib buf中,依然處於用戶態,如果此時應用進程crash掉,這些數據將丟失。
  • 在調用fflush可將clib buf中的數據寫入內核的page cache中。
  • 調用fclose也會將clib buff中的數據刷新到內核,並且把clib buff中的輸入數據丟棄。
    從這些標准IO的API可看出,標准IO比文件IO要簡潔很多,沒有各種標識,沒有sync, nonblock等。
    上列API具體使用細節可參考《unix環境高級編程》第5章。

文件IO

文件IO是直接操作linux系統調用,大部分的問題都是使用文件IO帶來的。

api


int open(const char *pathname, int oflag);

int close(int filedes);

ssize_t read(int filedes, void* buff, size_t nbytes);

ssize_t write(int filedes, const void* buff, size_t nbytes);

int fsync(int filedes);

int fcntl(int filedes, int cmd);

int ioctl(int filedes, int request);

說明

  • O_SYNC標識打開的文件,會在write系統調用時,會等待IO從底層返回;O_SYNC僅對寫有意義。
  • O_DIRECT標識打開的文件不經過page cache; O_DIRECT對讀寫都是有意義的。
  • O_NONBLOCK標識打開的文件(一般是網絡IO,終端設備IO) ,在不可讀寫時立即返回EAGAIN等錯誤碼。
  • O_SYNC, O_DIRECT有區別如下,
size_t wirte_file()
{
    if(o_DIRECT)
        direct_io();
    else
        buffered_io();

    if( O_SYNC )
        wait_data_synced();
}
上述API細節可參考《unix環境高級編程》第3章。

mmap

api

#include <sys/mman.h>
void *mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset);
mmap在calling process的虛擬地址空間中創建一個映射,主要有以下兩種常用方式:
  • 對文件創建一個mapping,讀寫文件可以用讀寫內存替代。

  • 匿名映射,傳入的fd為-1

    創建mapping后,省掉了數據從在用戶態buff和內核page cache的拷貝


后續整理下linux系統文件IO流程


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM