1. 程式人生 > >Linux通用I/O模型

Linux通用I/O模型

學習Linux系統程式設計,檔案I/O是一個不錯的切入點。首先,日常操作中或多或少都使用過檔案,有一定的概念;其次,檔案I/O可以由幾個最最基礎的系統呼叫完成,降低入門理解難度。

基礎系統呼叫

LinuxI/O操作是通用化的,不僅僅可以用來操作檔案輸入輸出,還可以用來操作管道、FIFOsocket、終端裝置等。將裝置抽象成一個檔案,用I/O操作控制裝置是類Unix系統一大特色。

最最基礎的I/O作業系統呼叫包括:

  • fd = open(pathname, flags, mode)
  • rlen = read(fd, buf, count)
  • wlen = write(fd, buf, count)
  • status = close(fd)

注意到,相關係統呼叫都圍繞檔案描述符fd展開。檔案描述符在下節詳細介紹。

另外,需要特別提示一下,系統呼叫函式介面(其實是庫函式封裝)可以通過man命令檢視詳細的引數、返回值及用法說明。比如,終端下執行man read,就可以看到read這個系統呼叫的相關文件說明:

man open

檔案描述符

I/O作業系統呼叫都以檔案描述符(一個非負整數),指代開啟的檔案。每個程序都有一個開啟檔案表,可以理解成一個數組,檔案描述符可以理解成陣列的下標。相關I/O作業系統呼叫以檔案描述符為引數,便可以通過陣列訪問定位到指定的檔案物件,進而進行I/O

操作。

一般情況下,程序的標準輸入輸出由3個特定的檔案描述符指定,列舉如下:

檔案描述符 用途 POSIX名稱 stdio流
0 標準輸入 STDIN_FILENO stdin
1 標準輸出 STDOUT_FILENO stdout
2 標準錯誤 STDERR_FILENO stderr

正常情況下,程式在開始執行之前,由shell準備好這3個檔案描述符。更準確的說法是,程式繼承了shell

檔案描述符的副本,一般是指向shell所在的終端。當然了,可以通過在shell中對輸入/輸出進行重定向或者在程式啟動後關閉並重新開啟檔案描述符,修改檔案描述符指向。

實戰案例

讀檔案

首先,通過一個例子,探索一下如何通過I/O作業系統呼叫讀取檔案內容並輸出:

#include <stdio.h>
#include <fcntl.h>

int
main(int argc, char *argv[])
{
    // 開啟檔案
    int fd = open("a.txt", O_RDONLY);
    if (-1 == fd)
    {
        perror("fail to open a.txt");
        return -1;
    }

    // 準備緩衝區並讀檔案
    char buf[1024];
    int rlen = read(fd, buf, sizeof(buf)-1);
    if (-1 == rlen)
    {
        perror("fail to read a.txt");
        return -2;
    }

    // 輸出內容
    buf[rlen] = '\0';
    printf("read %d bytes, which is:\n", rlen);
    printf("%s\n", buf);

    // 關閉檔案
    int status = close(fd);
    if (-1 == status)
    {
        perror("fail to close a.txt");
        return -3;
    }

    return 0;
}

寫檔案

#include <stdio.h>
#include <string.h>
#include <fcntl.h>

int
main(int argc, char *argv[])
{
    // 開啟檔案
    int fd = open("a.txt", O_WRONLY);
    if (-1 == fd)
    {
        perror("fail to open a.txt");
        return -1;
    }

    // 準備資料並寫到檔案
    char data[] = "hello, this is line written by write syscall\n";
    int wlen = write(fd, data, strlen(data));
    if (-1 == wlen)
    {
        perror("fail to read a.txt");
        return -2;
    }

    // 輸出成功寫入位元組數
    printf("write %d bytes of %d total\n", wlen, strlen(data));

    // 關閉檔案
    int status = close(fd);
    if (-1 == status)
    {
        perror("fail to close a.txt");
        return -3;
    }

    return 0;
}

 



作者:fasionchan
連結:https://www.jianshu.com/p/5357d72ef17d