Linux系统之----基础IO

1.基础概念:

文件与内容操作

文件由内容和属性组成。内容是文件存储的数据,而属性可能包括文件的创建时间、修改时间、权限等。对文件的操作可以分为对内容的操作和对属性的操作。

文件的打开

在访问一个文件之前,通常需要先将其打开。这是因为操作系统需要将文件加载到内存中,以便进行读写操作。如果一个文件没有被打开,它就存在于磁盘上,而不是在内存中

谁打开文件

用户可以通过命令行(如bash)启动进程来打开文件。进程是操作系统进行资源分配和调度的基本单位。

操作系统的角色

操作系统负责管理文件的打开和关闭。它确保进程能够安全地访问文件,并且在不需要时释放资源。操作系统通过系统调用(如open)来打开文件,这是进程与操作系统交互的一种方式。

文件描述符

操作系统使用文件描述符来跟踪每个打开的文件。文件描述符是一个数字,用于在程序中引用特定的文件。一定存在一种数据结构体(如进程控制块PCB)来描述被打开的文件,这有助于操作系统管理文件的打开状态。

进程与文件的关系

进程有task_struct,这是操作系统用来描述进程的数据结构。它包含了进程的状态信息,包括打开的文件。研究进程与文件的关系,实际上是研究进程如何通过操作系统来访问和管理文件。

2.fopen函数:

2.1 函数原型

2.2 参数解释

pathname就是路径名,就是你想打开的那个文件的路径

mode是指文件的打开模式,具体的模式可以参考下图

只读模式 ("r") :打开一个已经存在的文件,用于读取操作。如果文件不存在,返回 NULL

写入模式 ("w") :打开一个文件,用于写入操作。如果文件不存在,创建新文件。如果文件已存在,清空文件内容。

追加模式 ("a"):打开一个文件,用于追加写入操作。如果文件不存在,创建新文件。如果文件已存在,写入内容追加到文件末尾。

读写模式 ("r+"):打开一个已经存在的文件,用于读写操作。文件指针放在文件的开头。

写入和读取模式 ("w+"):打开一个文件,用于读写操作。如果文件不存在,创建新文件。如果文件已存在,清空文件内容。文件指针放在文件的开头。

追加和读取模式 ("a+"):打开一个文件,用于追加写入和读取操作。如果文件不存在,创建新文件。如果文件已存在,写入内容追加到文件末尾。文件指针放在文件的末尾。

二进制只读模式 ("rb"):类似于只读模式,但用于二进制文件。

二进制写入模式 ("wb"):类似于写入模式,但用于二进制文件。

二进制追加模式 ("ab"):类似于追加模式,但用于二进制文件。

二进制读写模式 ("rb+"):类似于读写模式,但用于二进制文件。

二进制写入和读取模式 ("wb+"):类似于写入和读取模式,但用于二进制文件。

二进制追加和读取模式 ("ab+"):类似于追加和读取模式,但用于二进制文件。

2.3 返回值

成功时,fopen 返回一个指向 FILE 结构的指针,该结构用于后续的文件操作。如果打开文件失败,返回 NULL,并设置 errno 以指示错误原因。

2.4 错误处理

如果文件打开失败,可以通过检查返回值是否为 NULL 来确定。可以使用 perrorstrerror 函数来获取错误描述。

2.5 代码示例

复制代码
#include <stdio.h>

int main() {
    FILE *fp;
    fp = fopen("example.txt", "r"); // 以只读模式打开文件

    if (fp == NULL) {
        perror("Error opening file");
        return -1;
    }

    // 进行文件操作...

    fclose(fp); // 关闭文件
    return 0;
}

2.6 注意事项

1、文件指针fopen 返回的 FILE 指针用于后续的文件读写操作。

2、文件路径fopen 需要文件的完整路径或相对于当前工作目录的路径。当前工作目录(CWD)可以通过 getcwd 函数获取。

3、文件模式:不同的模式允许不同的文件操作,如读取、写入、追加等。

4、使用 fopen 打开文件后,应该在完成文件操作后调用 fclose 来关闭文件,以释放资源。

5、在处理文件时,始终检查 fopen 的返回值,以确保文件正确打开。

3.echo

当我们输入echo "hello word" > log.txt的时候,会重定向到log.txt文件中,必须先打开这个文件,之后才能写入,默认是w方式,所以我们下次写的时候如果用>,原文件内容就会被清空,而如果使用>>就不会

4.输出信息到显示器的方法

1.通过键盘输入数字(如12345),讨论输入的是int 12345还是一个1 2 3 4 5,答案是后者,说明显示器被叫做字符设备

2.我今天向显示器写入12345,我是写了一个int 12345 ,还是向显示器写入了int 12345?答案是向显示器写入了字符1 2 3 4 5 ,所以说显示器是字符设备!!

5.标准输入输出流

标准输入输出流:

stdin:标准输入流,通常与键盘文件关联。

stdout:标准输出流,通常与显示器文件关联。

stderr:标准错误流,通常与显示器文件关联,用于输出错误信息。

而我们的进程在启动的时候,会默认打开三个输入输出流,本质上就是打开三个文件,换句话说,凡是使用CPU计算的,都要进程默认打开对应的文件

那我们不妨来查看一下这三个标准流:

我们输入man 3 stdin

6.fopen

首先我们查看一下这个函数

6.1 参数解释

  1. pathname:

    • 文件路径和文件名。用于指定要打开或创建的文件。

2.flags:

打开文件的方式,由一组标志位组合而成。常用的标志包括:

O_RDONLY:以只读方式打开。

O_WRONLY:以只写方式打开。

O_RDWR:以读写方式打开

O_APPEND:写入时追加到文件末尾。

O_CREAT:如果文件不存在,则创建它,并使用mode参数指定的权限。

O_TRUNC:如果文件存在,则截断文件长度为0。

这些标志可以使用按位或运算符(|)组合,例如:

复制代码
open("file.txt", O_RDWR | O_CREAT, 0644);

实际上,这些每个标志都是一个宏,定义为一个数字,其中只有一个比特位是1,其他位是0。这样可以通过按位或运算符组合多个标志。

3.mode:

文件权限模式,用于指定新创建文件的权限。权限模式是一个mode_t类型的值,通常由以下三位权限组成:即前文所讲的rwx,也可以用数字表示,如666是所有权限均为可读可写,rw-

注意:

1.如果文件已经存在,可以只使用两个参数(pathnameflags)来打开文件

6.2 位图传递标志位

6.2.1 定义

位图传递标志位是一种通过位运算组合多个标志位的方法。在文件操作中,标志位用于指定文件的打开模式(如只读、只写、读写、追加等)。每个标志位是一个单独的位,通过按位或运算符(|)将它们组合在一起。

6.2.2 常见的标志位总结

标志位 描述
O_RDONLY 以只读方式打开文件
O_WRONLY 以只写方式打开文件
O_RDWR 以读写方式打开文件
O_APPEND 写入时追加到文件末尾
O_CREAT 如果文件不存在,则创建文件
O_TRUNC 如果文件存在,则截断文件长度为0
O_EXCL O_CREAT一起使用,如果文件已存在则打开失败

6.2.3 位图传递标志位的原理

每个标志位对应一个独立的位,通常定义为宏,表示为一个数字,其中只有一个比特位为1。例如

复制代码
#define O_RDONLY  00
#define O_WRONLY  01
#define O_RDWR    02
#define O_APPEND  04
#define O_CREAT   0100
#define O_TRUNC   01000
#define O_EXCL    02000

这些宏定义允许通过按位或运算符组合多个标志位。例如:

复制代码
int flags = O_RDWR | O_APPEND | O_CREAT;

上述代码组合了读写模式、追加模式和创建模式。

6.2.4 优点

灵活性:允许组合多个标志位,满足不同的文件操作需求。

可读性:通过宏定义,使代码更具可读性,易于理解和维护。

跨平台性 :位图传递标志位在不同操作系统上可能具有不同的定义,但其使用方式类似。跨平台编程中,标准库函数(如fopen)会封装这些差异,提供统一的接口。

7.文件描述符

7.1 定义

在操作系统中,文件描述符(File Descriptor,FD)是一个用于访问文件的整数,它是一个数组索引,指向内核中的文件描述符表。文件描述符表维护了文件的状态和操作信息。

7.2 文件描述符的管理

内核管理:每个进程都维护着一个文件描述符表,包含多个文件描述符。内核通过这些描述符来管理文件的打开、读取、写入和关闭操作。

标准文件描述符:通常,进程启动时会默认打开三个文件描述符:

0:标准输入(stdin

1:标准输出(stdout

2:标准错误(stderr

7.3 跨平台性

跨平台性是指软件能够在多种不同的操作系统上运行,无需修改或只需少量修改。在文件操作中,不同操作系统(如Linux、Windows、macOS)可能有不同的文件接口和实现方式。

7.3.1为什么需要跨平台性?

1.提高语言竞争力:支持跨平台可以让编程语言吸引更广泛的用户群体,提升其使用率和影响力。

2.便捷性:开发者无需针对不同平台编写不同代码,降低了开发成本和复杂度。

7.3.2 如何实现跨平台性?

标准库封装 :高级语言通常会提供标准库封装底层的系统调用,如C语言的<stdio.h>库。这些库在不同平台上实现细节可能不同,但对开发者提供了统一的接口。

Linux :调用openread等系统调用。

Windows :调用CreateFileReadFile等API。

条件编译 :开发者使用条件编译指令(如#ifdef)来编写可在不同平台运行的代码。

复制代码
#ifdef LINUX
    // Linux系统调用
#elif defined(WIN32)
    // Windows API调用
#endif
相关推荐
untE EADO3 分钟前
Nginx代理到https地址忽略证书验证配置
运维·nginx·https
空中海16 分钟前
02. 静态逆向、Manifest 分析与 Smali 重打包
服务器·网络·windows
dvjr cloi28 分钟前
Linux(CentOS)安装 MySQL
linux·mysql·centos
江南十四行34 分钟前
AI Agent应用类型及Function Calling开发实战(三)
服务器·前端·javascript
炘爚36 分钟前
TCP三次握手和四次挥手
服务器·网络·tcp/ip
zhouwy11340 分钟前
Linux系统管理命令大全
linux·运维
zhangrelay1 小时前
三分钟云课实践速通--单片机原理与应用--Arduino--SimulIDE--
linux·单片机·嵌入式硬件·学习·ubuntu
zzzyyy5381 小时前
Linux之缓冲区
linux·运维·服务器
hwscom1 小时前
Linux服务器如何进行安全加固,防止黑客攻击(Windows也适用)
linux·服务器·安全
lzh200409192 小时前
Linux管道(Pipe)深度指南:从原理到实战
linux·c++