《深入浅出 Linux 基础 I/O 操作:从标准库到文件系统》

文章目录

  • 前言
    • [1. I/O 的分类与基础概念](#1. I/O 的分类与基础概念)
      • [文件与 I/O 的基本概念](#文件与 I/O 的基本概念)
    • [2. 标准库 I/O 接口](#2. 标准库 I/O 接口)
      • [2.1 文件操作](#2.1 文件操作)
      • [2.2 数据读写](#2.2 数据读写)
      • [2.3 文件定位](#2.3 文件定位)
    • [3. 系统调用 I/O 接口](#3. 系统调用 I/O 接口)
      • [3.1 打开与关闭文件](#3.1 打开与关闭文件)
      • [3.2 读写数据](#3.2 读写数据)
      • [3.3 文件定位](#3.3 文件定位)
    • [4. 文件描述符](#4. 文件描述符)
    • [5. 重定向](#5. 重定向)
      • [5.1 标准重定向](#5.1 标准重定向)
      • [5.2 文件描述符重定向](#5.2 文件描述符重定向)
      • [5.3 使用 dup2 实现重定向](#5.3 使用 dup2 实现重定向)
    • [6. 文件描述符与流的关系](#6. 文件描述符与流的关系)
    • [7. 文件系统与缓冲区](#7. 文件系统与缓冲区)
      • [7.1 文件系统](#7.1 文件系统)
      • [7.2 缓冲区](#7.2 缓冲区)
    • [8. 软链接 与 硬链接](#8. 软链接 与 硬链接)
      • [8.1 软链接(Symbolic Link)](#8.1 软链接(Symbolic Link))
      • [8.2 硬链接(Hard Link)](#8.2 硬链接(Hard Link))
      • [8.3 软链接与硬链接的区别](#8.3 软链接与硬链接的区别)

前言

Linux 操作系统以其高效、灵活的 I/O 机制闻名,它不仅为开发者提供了丰富的接口,还在底层设计上注重性能与可靠性。下面我们将从多角度解析 Linux 的基础 I/O,涵盖从文件读写到文件描述符、重定向、缓冲区管理以及异步 I/O 的方方面面,理清基础 I/O 在 Linux 中的全貌。


1. I/O 的分类与基础概念

在 Linux 中,I/O 操作分为两大类:

  1. 标准库 I/O:基于标准 C 库(libc),如 fopenfread 等,提供高层次接口,支持缓冲操作。
  2. 系统调用 I/O:直接调用内核的接口,如 openread 等,提供底层控制。

文件与 I/O 的基本概念

  • 文件描述符(File Descriptor):内核用来标识文件的一个整数值,是 Linux 一切 I/O 操作的核心。
  • 流(Stream):标准库 I/O 操作使用流的抽象,与文件描述符有对应关系。
  • 缓冲区:用于提高性能的数据缓存区。

2. 标准库 I/O 接口

标准库提供了一组简单易用的文件操作接口,这些接口基于流(FILE*)的抽象。

FILE* 是 C 标准库中定义的一个数据类型,用于表示文件流(file stream

2.1 文件操作

  • fopenfclose:用于打开和关闭文件。

    c 复制代码
    FILE *file = fopen("example.txt", "r");
    if (file) fclose(file);
  • 模式选项:

    • "r":只读打开。
    • "w":写入打开,清空文件。
    • "a":追加模式打开。
    • "b":二进制模式(可组合)。

2.2 数据读写

  • 文本读写

    • fgetsfputs:按行操作文本。
    c 复制代码
    char line[256];
    fgets(line, sizeof(line), file);  // 从文件读取一行
    fputs(line, stdout);             // 输出到标准输出
  • 格式化读写

    • fprintffscanf:支持格式化操作。
    c 复制代码
    fprintf(file, "Name: %s, Age: %d\n", name, age);
    fscanf(file, "%s %d", name, &age);
  • 二进制读写

    • freadfwrite:适用于结构体或块数据操作。
    c 复制代码
    char buffer[512];
    size_t bytesRead = fread(buffer, sizeof(char), 512, file);
    fwrite(buffer, sizeof(char), bytesRead, anotherFile);

2.3 文件定位

  • fseek:调整文件指针位置。

    c 复制代码
    fseek(file, 0, SEEK_END);  // 移动到文件末尾
  • ftell:获取当前位置。

    c 复制代码
    long pos = ftell(file);
  • rewind:快速返回文件开头。

    c 复制代码
    rewind(file);

3. 系统调用 I/O 接口

系统调用是 Linux 文件 I/O 的基础,提供底层控制,灵活性更强。

3.1 打开与关闭文件

  • openclose

    c 复制代码
    int fd = open("example.txt", O_RDWR | O_CREAT, 0644);
    if (fd != -1) close(fd);
  • 模式选项:

    • O_RDONLY:只读。
    • O_WRONLY:只写。
    • O_RDWR:读写。
    • O_CREAT:文件不存在时创建。

3.2 读写数据

  • readwrite

    c 复制代码
    char buffer[256];
    ssize_t n = read(fd, buffer, sizeof(buffer));
    write(fd, buffer, n);

3.3 文件定位

  • lseek:调整文件偏移。

    c 复制代码
    off_t offset = lseek(fd, 0, SEEK_CUR);  // 获取当前位置

4. 文件描述符

文件描述符是 Linux I/O 操作的核心抽象,每个打开的文件、管道、网络连接都有一个唯一的描述符。

  • 标准文件描述符
    • 0:标准输入(stdin)。
    • 1:标准输出(stdout)。
    • 2:标准错误(stderr)。

5. 重定向

在 Linux 中,重定向是一种将命令的输入或输出从默认位置(如终端)重定向到其他目标(如文件或设备)的功能。常见的重定向操作包括将输出写入文件或从文件读取输入。

除了在 shell 中使用符号(如 ><)实现重定向,开发者还可以通过系统调用 dup2 在程序中动态重定向文件描述符。

5.1 标准重定向

  • 输出重定向:

    bash 复制代码
    $ echo "Hello" > output.txt
  • 输入重定向:

    bash 复制代码
    $ wc -l < input.txt

5.2 文件描述符重定向

  • 重定向错误输出:

    bash 复制代码
    $ command 2> error.log
  • 同时重定向标准输出和错误输出:

    bash 复制代码
    $ command > output.log 2>&1

5.3 使用 dup2 实现重定向

dup2 是一个系统调用,用于将一个文件描述符复制到另一个文件描述符,从而实现重定向。

c 复制代码
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>

int main() {
    int fd = open("output.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    // 重定向标准输出到文件
    dup2(fd, STDOUT_FILENO);
    close(fd);

    // 输出内容将被写入 output.txt 而不是终端
    printf("Hello, this text is redirected to a file!\n");

    return 0;
}

在上面的例子中,dup2 将标准输出(文件描述符 STDOUT_FILENO)重定向到 output.txt。此后的所有标准输出操作都会写入该文件,而不是显示在终端中。


6. 文件描述符与流的关系

文件描述符是底层的整数标识符,由内核分配,用于标识打开的文件、管道或设备;而流(FILE*)是标准库(如 stdio.h)提供的高级抽象,用于缓冲和格式化的 I/O 操作。

  • 文件流指针结构中包含了文件描述符成员

  • 流(FILE*)通过 fopen 创建。

  • 描述符由 open 返回。

二者转换:

  • 文件流转描述符:

    c 复制代码
    int fd = fileno(file);
  • 描述符转文件流:

    c 复制代码
    FILE *file = fdopen(fd, "r");

7. 文件系统与缓冲区

7.1 文件系统

Linux 文件系统支持多种类型(如 ext4、XFS、NTFS 等),提供对存储设备的抽象。

  • 文件类型
    • 普通文件:存储数据。
    • 目录文件:组织文件。
    • 设备文件:如 /dev/sda
    • 套接字:如 /var/run/docker.sock

7.2 缓冲区

标准 I/O 默认启用缓冲区:

  • 全缓冲:如文件流。
  • 行缓冲:如标准输出。
  • 无缓冲:如标准错误。

缓冲区模式可通过 setvbuf 调整:

c 复制代码
setvbuf(file, NULL, _IONBF, 0);  // 设置无缓冲模式

在 Linux 文件系统中,软链接(symbolic link)硬链接(hard link) 是两种实现文件共享或别名的方法。它们有不同的特性和用途。


8. 软链接 与 硬链接

8.1 软链接(Symbolic Link)

软链接是一个独立的文件,它包含指向另一个文件或目录的路径。软链接类似于 Windows 中的快捷方式。

特点</font>

  1. 独立存在:软链接是一个实际的文件,与被链接的目标文件分开存储。
  2. 路径指向:软链接存储的是目标文件的路径(绝对路径或相对路径)。
  3. 可以跨文件系统:软链接可以指向不同的分区或文件系统上的文件。
  4. 链断后无效:如果目标文件被删除或移动,软链接会变成无效的"断链"。

创建软链接

使用 ln -s 命令:

bash 复制代码
ln -s target_file symbolic_link

示例代码

bash 复制代码
$ echo "Hello" > original.txt
$ ln -s original.txt link.txt
$ cat link.txt
Hello
$ rm original.txt
$ cat link.txt
cat: link.txt: No such file or directory

8.2 硬链接(Hard Link)

硬链接是一个直接引用目标文件的文件系统对象。它们指向文件的同一个物理数据块。

特点

  1. 共享文件数据:硬链接与目标文件共享相同的 inode,多个硬链接是文件的多个别名。
  2. 不可跨文件系统:硬链接只能在同一个分区或文件系统内创建。
  3. 目标文件不可删除:目标文件的实际数据只有当所有硬链接都被删除后才会被释放。
  4. 链不会断:即使删除目标文件,其数据仍然可以通过硬链接访问。

创建硬链接

使用 ln 命令(不带 -s 选项):

bash 复制代码
ln target_file hard_link

示例代码

bash 复制代码
$ echo "Hello" > original.txt
$ ln original.txt hardlink.txt
$ rm original.txt
$ cat hardlink.txt
Hello

8.3 软链接与硬链接的区别

特性 软链接 硬链接
指向 指向目标文件的路径 指向目标文件的 inode
文件系统 可以跨文件系统 只能在同一个文件系统内
是否独立 是一个独立文件 是文件的额外别名
目录支持 可以链接目录(需要特权) 不支持
目标文件删除影响 链接失效 链接仍然有效

总结

  • 软链接:更灵活,支持跨文件系统,链断后失效,适用于快捷方式场景。
  • 硬链接:更稳固,多个硬链接共享同一数据块,适用于需要冗余访问或保护文件内容的场景。
相关推荐
liuweni3 分钟前
Next.js系统性教学:深入理解缓存交互与API缓存管理
开发语言·前端·javascript·经验分享·缓存·前端框架·交互
AI人H哥会Java19 分钟前
【JAVA】Java高级:多数据源管理与Sharding:在Spring Boot应用中实现多数据源的管理
java·开发语言
Thomas_YXQ20 分钟前
Unity3D项目为什么要使用FairyGUI
开发语言·unity·游戏引擎·unity3d·游戏开发
uyeonashi32 分钟前
【C++】刷题强训(day14)--乒乓球匡、组队竞赛、删除相邻数字的最大分数
开发语言·c++·算法·哈希算法
黑客呀32 分钟前
网络安全——防火墙
服务器·网络·php
egekm_sefg1 小时前
【Golang】——Gin 框架中的模板渲染详解
开发语言·golang·gin
明金同学1 小时前
腾讯云海外服务器Window切换为linux系统(从Window DD 到 Linux)
linux·服务器·腾讯云
在在进步1 小时前
R学习——数据框
开发语言·r语言
大G哥1 小时前
27. 聚类分析 - 使用R进行客户分群
开发语言·信息可视化·r语言
我不是程序猿儿2 小时前
【C#】反射 和 特性(Attribute)、[AttributeUsage(AttributeTargets.Property)]
开发语言·c#