深入探究Linux文件系統I/O

一、基礎概念

什麼是文件系統?

文件系統,即 File System,是指計算機使用的一類存儲媒介的物理組織和邏輯管理方式,它維護了對存儲媒介的訪問和管理。

那麼什麼是 Linux 文件系統?

Linux 文件系統是在 Linux 操作系統上,對存儲設備進行的一種邏輯組織形式。Linux 文件系統一般由三部分構成:超級塊、索引節點(inode)、數據塊。其中超級塊記錄著文件系統的元信息;索引節點記錄著文件和目錄的元數據;數據塊儲存着文件和目錄的實際內容。

Linux 文件系統中的 I/O 是什麼?

I/O 即 Input/Output,也就是 Linux 文件系統中的讀寫操作。讀操作是指從存儲設備中讀取數據到內存中,而寫操作則是將內存中的數據寫入到存儲設備中。I/O 操作是 Linux 文件系統中最基本的操作方式。

二、I/O 操作方式

Linux 文件系統中的 I/O 操作可以分為同步和異步兩種方式。

1. 同步 I/O

同步 I/O 是指應用程序在執行 I/O 操作時,必須等待 I/O 操作結束後才能繼續執行後續的操作。同步 I/O 的特點是操作可靠,但一旦發生阻塞,就會嚴重影響應用程序的性能。

#include 
#include 
#include 
#include 

int main(void)
{
    int fd;
    char buf[1024];

    fd = open("test.txt", O_RDONLY);
    if (fd == -1) {
        printf("File open error!\n");
        return -1;
    }

    read(fd, buf, 1024);

    printf("%s", buf);

    close(fd);
    return 0;
}

2. 異步 I/O

異步 I/O 是指應用程序在執行 I/O 操作時,無須等待 I/O 操作結束,可以先執行後續的操作,待 I/O 操作完成後再執行回調函數。異步 I/O 的特點是操作效率高,但開發難度較大。

#include 
#include 
#include 
#include 
#include 

void handle_read(int signum)
{
    printf("Asynchronous I/O operation completed!\n");
}

int main(void)
{
    int fd;
    char buf[1024];
    struct sigaction sa;

    fd = open("test.txt", O_RDONLY);
    if (fd == -1) {
        printf("File open error!\n");
        return -1;
    }

    sa.sa_flags = 0;
    sa.sa_handler = handle_read;
    sigemptyset(&sa.sa_mask);

    if (sigaction(SIGIO, &sa, NULL) == -1) {
        printf("Signal handler registration error!\n");
        return -1;
    }

    fcntl(fd, F_SETOWN, getpid());
    fcntl(fd, F_SETFL, O_ASYNC);

    while (1) {
        sleep(1);
    }

    close(fd);
    return 0;
}

三、I/O 多路復用

I/O 多路復用是指讓一個或多個進程能夠同時監聽多個文件描述符的可讀可寫狀態,從而實現多路 I/O 服務。在 Linux 文件系統中,I/O 多路復用主要有 select、poll 和 epoll 三種機制。

1. select

select 是最早實現 I/O 多路復用的方法之一。通過 select 實現 I/O 多路復用需要將待監控的文件描述符加入到 fd_set 集合中,並設置超時時間。select 函數將會阻塞進程,直到有文件描述符發生變化或超時。select 函數會返回發生變化的文件描述符的個數。

#include 
#include 
#include 
#include 
#include 

int main()
{
    fd_set rfds;
    struct timeval tv;
    int retval;

    FD_ZERO(&rfds);
    FD_SET(0, &rfds);

    tv.tv_sec = 5;
    tv.tv_usec = 0;

    retval = select(1, &rfds, NULL, NULL, &tv);
    if (retval == -1) {
        printf("select error!\n");
        exit(EXIT_FAILURE);
    } else if (retval) {
        printf("Data is available now.\n");
    } else {
        printf("No data within five seconds.\n");
    }

    return 0;
}

2. poll

poll 是比 select 更加高效的 I/O 多路復用方法之一。poll 的實現方式與 select 類似,但其使用鏈表來存儲被監控的文件描述符集,解決了 select 方法中文件描述符數量的限制問題。

#include 
#include 
#include 
#include 

int main()
{
    struct pollfd fds[1];
    int retval;

    fds[0].fd = STDIN_FILENO;
    fds[0].events = POLLIN;

    retval = poll(fds, 1, 5000);
    if (retval == -1) {
        printf("poll error!\n");
        exit(EXIT_FAILURE);
    } else if (retval) {
        printf("Data is available now.\n");
    } else {
        printf("No data within five seconds.\n");
    }

    return 0;
}

3. epoll

epoll 是 Linux 的高級 I/O 多路復用方法。epoll 通過 epoll_create 函數創建 epoll 實例,然後使用 epoll_ctl 函數來向 epoll 中添加、刪除、修改被監控的文件描述符。epoll_wait 函數則是阻塞等待文件描述符狀態變化的發生,並返回變化的文件描述符集。

#include 
#include 
#include 
#include 

#define MAX_EVENTS 10

int main(int argc, char *argv[])
{
    int sockfd;
    struct epoll_event event;
    struct epoll_event event_array[MAX_EVENTS];
    int epoll_fd, nfds, i;

    sockfd = create_and_bind("8080");
    if (sockfd == -1) exit(EXIT_FAILURE);

    if (make_socket_non_blocking(sockfd) == -1) exit(EXIT_FAILURE);

    if (listen(sockfd, SOMAXCONN) == -1) exit(EXIT_FAILURE);

    epoll_fd = epoll_create1(0);
    if (epoll_fd == -1) exit(EXIT_FAILURE);

    event.data.fd = sockfd;
    event.events = EPOLLIN | EPOLLET;

    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sockfd, &event) == -1) exit(EXIT_FAILURE);

    while (1) {
        nfds = epoll_wait(epoll_fd, event_array, MAX_EVENTS, -1);
        for (i = 0; i < nfds; i++) {
            if (event_array[i].events & EPOLLIN) {
                if (event_array[i].data.fd == sockfd) {
                    while (1) {
                        int conn_sock = accept(sockfd, NULL, NULL);
                        if (conn_sock == -1) {
                            if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
                                break;
                            } else {
                                perror("accept");
                                break;
                            }
                        }

                        make_socket_non_blocking(conn_sock);

                        event.data.fd = conn_sock;
                        event.events = EPOLLIN | EPOLLET;

                        if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, conn_sock, &event) == -1) exit(EXIT_FAILURE);
                    }
                } else {
                    do_use_fd(event_array[i].data.fd);
                }
            }
        }
    }

    close(sockfd);
    return 0;
}

四、文件映射技術

文件映射(Memory Mapping)是指操作系統將文件的一段內容直接映射到進程的地址空間,使得進程可以直接訪問文件內容,從而加快了文件 I/O 的速度。在 Linux 文件系統中,文件映射可以使用 mmap 函數來實現。

#include 
#include         
#include           
#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{
    int fd;
    char *mapped;
    struct stat file_stat;

    fd = open(argv[1], O_RDONLY);
    if (fd == -1) exit(EXIT_FAILURE);

    if (fstat(fd, &file_stat) == -1) exit(EXIT_FAILURE);

    mapped = mmap(NULL, file_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
    if (mapped == MAP_FAILED) exit(EXIT_FAILURE);

    printf("%s", mapped);

    if (munmap(mapped, file_stat.st_size) == -1) exit(EXIT_FAILURE);

    close(fd);
    return 0;
}

原創文章,作者:FABYO,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/370137.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
FABYO的頭像FABYO
上一篇 2025-04-18 13:40
下一篇 2025-04-18 13:40

相關推薦

  • 分佈式文件系統數據分佈算法

    數據分佈算法是分佈式文件系統中的重要技術之一,它能夠實現將文件分散存儲於各個節點上,提高系統的可靠性和性能。在這篇文章中,我們將從多個方面對分佈式文件系統數據分佈算法進行詳細的闡述…

    編程 2025-04-27
  • 如何在Linux中添加用戶並修改配置文件

    本文將從多個方面詳細介紹在Linux系統下如何添加新用戶並修改配置文件 一、添加新用戶 在Linux系統下創建新用戶非常簡單,只需使用adduser命令即可。使用以下命令添加新用戶…

    編程 2025-04-27
  • 如何解決linux jar包 invalid or corrupt jarfile問題

    對於許多開發人員和系統管理員在Linux環境下使用Java開發過程中遇到的一個常見的問題是 invalid or corrupt jarfile(無效或損壞的jar文件)錯誤。當您…

    編程 2025-04-27
  • 在Linux上安裝JRE並配置環境變量

    本文將從以下幾個方面為您詳細闡述如何在Linux系統上,通過自己賬戶安裝JRE,並且配置環境變量。 一、安裝JRE 在進行安裝前,我們需要下載JRE的安裝包並解壓,可以從官方網站下…

    編程 2025-04-27
  • GTKAM:Linux下的照片管理器

    GTKAM是用於Linux操作系統的一款照片管理器,它支持多種相機及存儲設備,並提供了一系列強大的工具,讓用戶可以方便地瀏覽、管理、編輯和導出照片。本文將從多個方面對GTKAM進行…

    編程 2025-04-27
  • Linux sync詳解

    一、sync概述 sync是Linux中一個非常重要的命令,它可以將文件系統緩存中的內容,強制寫入磁盤中。在執行sync之前,所有的文件系統更新將不會立即寫入磁盤,而是先緩存在內存…

    編程 2025-04-25
  • Linux修改文件名命令詳解

    在Linux系統中,修改文件名是一個很常見的操作。Linux提供了多種方式來修改文件名,這篇文章將介紹Linux修改文件名的詳細操作。 一、mv命令 mv命令是Linux下的常用命…

    編程 2025-04-25
  • 深入解析Vue3 defineExpose

    Vue 3在開發過程中引入了新的API `defineExpose`。在以前的版本中,我們經常使用 `$attrs` 和` $listeners` 實現父組件與子組件之間的通信,但…

    編程 2025-04-25
  • 深入理解byte轉int

    一、位元組與比特 在討論byte轉int之前,我們需要了解位元組和比特的概念。位元組是計算機存儲單位的一種,通常表示8個比特(bit),即1位元組=8比特。比特是計算機中最小的數據單位,是…

    編程 2025-04-25
  • 深入理解Flutter StreamBuilder

    一、什麼是Flutter StreamBuilder? Flutter StreamBuilder是Flutter框架中的一個內置小部件,它可以監測數據流(Stream)中數據的變…

    編程 2025-04-25

發表回復

登錄後才能評論