当前位置: 首页 > article >正文

Linux:一切皆文件

**文件描述符**:它是一种特殊的索引,本质上是进程中`file_struct`结构体成员`fd_array`数组的下标。在Linux等系统中,文件描述符是一个非负整数,用于标识打开的文件,是内核为了高效管理已被打开的文件所创建的索引。通过文件描述符,进程可以对相应文件进行读写等操作。
- **文件打开模式**:分为主模式和副模式。
    - **主模式**:
        - `O_RDONLY`:以只读模式打开文件,即只能从文件中读取数据,不能进行写入操作。
        - `O_WRONLY`:以只写模式打开文件,只能向文件写入数据,无法读取。
        - `O_RDWR`:以读写模式打开文件,既可以读取数据也可以写入数据。
    - **副模式**:
        - `O_CREAT`:当指定文件不存在时,会自动创建该文件。
        - `O_APPEND`:追加模式,写入数据时会将数据添加到文件末尾,而不是覆盖原有内容。
        - `O_DIRECT`:直接I/O模式,绕过系统缓存,数据直接在用户空间和磁盘之间传输,通常用于对I/O性能有较高要求的场景。
        - `O_SYNC`:同步模式,保证每次写入操作都将数据同步到磁盘,确保数据的持久性,但可能会降低写入性能。
        - `O_NONBLOCK`:非阻塞模式,在进行I/O操作时,不会使进程阻塞等待,而是立即返回,常用于需要同时处理多个I/O操作的场景。

系统I/O编程

另外一个当然是标准I/O编程。这个后面再说。

(Linux 文件体系结构) 

  • open
  • write
  • read
  • Iseek
  • close
  • 伪代码示例:
    • int fd;
    • fd = open(filename, flags, mode);
    • lseek(fd, offset, whence)
    • write(fd, buf, write_len);
    • read(fd, buf, readlen);
    • close(fd);
  • 文件描述符:一个特殊的索引,用于标识被打开的文件或其他输入/输出资源。
  • 进程:是计算机中已运行的程序实例。

open/close函数

// OPEN函数所需的头文件
#include <sys/types.h>
#include <sys/stat.h>  
#include <fcntl.h>

// OPEN函数原型
// 当文件存在时
int open(const char* pathname, int flags);

// 当文件不存在,需要创建文件时
int open(const char* pathname, int flags, int perms);

// 返回值
// 成功:返回文件描述符(一个非负整数)
// 失败:返回-1
// CLOSE函数所需的头文件
#include <unistd.h>

 完整例子:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h> 

int main() {
    int fd; // 声明文件描述符变量
    fd = open("./a.txt", O_RDONLY); // 以只读方式打开文件
    if (fd < 0) { // 如果打开文件失败
        printf("open error!!\n"); // 输出错误信息
    } else {
        
        // 这里可以添加代码来读取文件内容或进行其他操作
    }
    
    // 如果需要在文件打开成功后输出空行,可以在else分支中添加printf("\n");
    close(fd)
    return 0; // 程序正常结束
}

read和write函数

一、函数定义

  1. read函数
    • 功能:从文件描述符指向的文件中读取数据。
    • 原型ssize_t read(int fd, void *buf, size_t count);
    • 参数
      • fd:文件描述符,标识要读取的文件。
      • buf:指向存储读取数据的缓冲区的指针。
      • count:要读取的字节数。
    • 返回值:成功时返回读取的字节数(可能小于count),失败时返回-1。
  2. write函数
    • 功能:向文件描述符指向的文件中写入数据。
    • 原型ssize_t write(int fd, const void *buf, size_t count);
    • 参数
      • fd:文件描述符,标识要写入的文件。
      • buf:指向包含要写入数据的缓冲区的指针。
      • count:要写入的字节数。
    • 返回值:成功时返回写入的字节数(可能小于count),失败时返回-1。

二、使用方法

  • 在使用read和write函数之前,需要打开文件并获得文件描述符。
  • 调用read函数时,应确保缓冲区足够大以存储读取的数据。
  • 调用write函数时,应确保缓冲区中的数据是要写入文件的正确数据。
  • 读取或写入操作完成后,应检查返回值以确定操作是否成功。

三、注意事项

  • 当读取或写入的数据量较大时,可能需要多次调用read或write函数。
  • 在读取或写入过程中,如果遇到错误(如文件结束、磁盘满等),read或write函数将返回-1,并设置errno以指示错误类型。
  • 在使用完文件后,应关闭文件描述符以释放资源。

复制普通文件实验步骤

  1. 打开要复制的文件
    • 使用适当的文件打开函数或方法,以只读模式打开源文件。
  2. 创建新的文件
    • 使用适当的文件创建函数或方法,以写模式创建一个新的目标文件。如果文件已存在,可以选择覆盖或报错。
  3. 把源文件内容读到缓冲区,把缓冲区内容写入新文件
    • 分配一个缓冲区来存储从源文件中读取的数据。
    • 使用文件读取函数或方法,从源文件中读取数据到缓冲区。
    • 使用文件写入函数或方法,将缓冲区中的数据写入到目标文件中。
  4. 循环执行第三步,直到读取的字节数量为0,退出循环
    • 重复执行第三步,直到文件读取函数或方法返回0,表示已经到达源文件末尾,没有更多的数据可以读取。
  5. 关闭打开的文件
    • 使用文件关闭函数或方法,关闭源文件和目标文件,释放资源。

代码:

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

#define BUFFER_SIZE 512

int main(int argc, char *argv[]) {
    int fd1, fd2;
    ssize_t read_size;
    char buffer[BUFFER_SIZE];

    // 检查命令行参数数量
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <source_file> <destination_file>\n", argv[0]);
        return EXIT_FAILURE;
    }

    // 打开源文件(只读)
    fd1 = open(argv[1], O_RDONLY);
    if (fd1 == -1) {
        perror("Error opening source file");
        return EXIT_FAILURE;
    }

    // 打开目标文件(写,如果文件不存在则创建)
    fd2 = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd2 == -1) {
        perror("Error opening destination file");
        close(fd1);
        return EXIT_FAILURE;
    }

    // 从源文件读取数据并写入目标文件
    while ((read_size = read(fd1, buffer, BUFFER_SIZE)) > 0) {
        if (write(fd2, buffer, read_size) != read_size) {
            perror("Error writing to destination file");
            close(fd1);
            close(fd2);
            return EXIT_FAILURE;
        }
    }

    // 检查read函数是否因为错误而返回-1
    if (read_size == -1) {
        perror("Error reading from source file");
    }

    // 关闭文件描述符
    close(fd1);
    close(fd2);

    return EXIT_SUCCESS;
}

标准I/O :

 

### C标准库实现了一个I/O缓存区
C标准库为了提高文件输入输出操作的效率,实现了一个I/O缓存区。在对文件进行读写操作时,数据不会立即写入磁盘或从磁盘读取,而是先在缓存区中进行处理。比如进行多次写入操作时,数据先存放在缓存区,等缓存区满或调用特定函数时才真正写入磁盘,这减少了磁盘I/O的次数,从而提升了性能。

### 常见标准I/O函数
- **fopen**:用于打开一个文件,返回一个指向文件的指针(`FILE*`类型),它需要指定文件名和打开模式(如"r" 只读、"w" 只写、"a" 追加等)。例如 `FILE *fp = fopen("test.txt", "r");` 尝试以只读模式打开名为"test.txt"的文件。
- **fclose**:用于关闭一个已打开的文件,它接受一个文件指针作为参数,在文件操作完成后应及时调用该函数关闭文件,释放相关资源,如 `fclose(fp);`。
- **fread**:从文件流中读取数据到指定的内存区域。它接受目标内存地址、每个数据项的大小、数据项的数量以及文件指针作为参数,返回实际读取的数据项数量。例如 `size_t count = fread(buffer, sizeof(char), 100, fp);` 尝试从文件指针 `fp` 指向的文件中读取100个字符到 `buffer` 中。
- **fwrite**:将数据从指定的内存区域写入到文件流中。参数与 `fread` 类似,接受源内存地址、每个数据项的大小、数据项的数量以及文件指针作为参数,返回实际写入的数据项数量。
- **fseek**:用于改变文件流的读写位置指针。它接受文件指针、偏移量以及起始位置(如 `SEEK_SET` 从文件开头、`SEEK_CUR` 从当前位置、`SEEK_END` 从文件末尾)作为参数。例如 `fseek(fp, 0, SEEK_END);` 将文件指针移动到文件末尾。
- **fflush**:强制把I/O缓存区中的数据写入到页缓存区。当需要确保数据及时写入文件时,可调用此函数,比如在一些日志记录场景中,希望数据尽快落盘就可以使用 `fflush` 。 

http://www.kler.cn/a/523517.html

相关文章:

  • C++中的类与对象(中)
  • Charles 4.6.7 浏览器网络调试指南:流量过滤与分析(六)
  • Mybatis是如何进行分页的?
  • 区块链的数学基础:核心原理与应用解析
  • Python 包管理工具 pip - pip 基础(安装包、升级包、卸载包、查看已安装的包、列出已安装的包)
  • RocketMQ原理—5.高可用+高并发+高性能架构
  • 差分约束系统 + spfa求最短路
  • 【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.19 排序革命:argsort的十大高阶用法
  • React中的JavaScript语法
  • MATLAB中fetchOutputs函数用法
  • 2007-2020年各省国内专利申请授权量数据
  • 【MySQL — 数据库增删改查操作】深入解析MySQL的 Update 和 Delete 操作
  • 【C++动态规划】2547. 拆分数组的最小代价|2019
  • 【论文投稿-第八届智能制造与自动化学术会议(IMA 2025)】HTML, CSS, JavaScript:三者的联系与区别
  • SOME/IP--协议英文原文讲解2
  • Python3 【函数】水平考试:精选试题和答案
  • MySQL数据导入与导出
  • MFC的绘制问题
  • p4:使用pytorch实现猴痘病识别
  • MySQL常用数据类型和表的操作
  • 【25美赛A题-F题全题目解析】2025年美国大学生数学建模竞赛(MCM/ICM)解题思路|完整代码论文集合
  • Linux 内核学习(4) --- devfreq 动态调频框架
  • 01学习预热篇(D6_正式踏入JVM深入学习前的铺垫)
  • An Attention Free Transformer论文参考文献
  • java 判断Date是上午还是下午
  • 基础IO(2)