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
相关推荐
YOYO--小天14 分钟前
RS485和RS232 通信配置
linux·嵌入式硬件
大蚂蚁2号26 分钟前
windows文件共享另一台电脑资源管理器网络文件夹无法找到机器
运维·服务器·网络
Lw老王要学习40 分钟前
Linux数据库篇、第一章_02_MySQL的使用增删改查
linux·运维·数据库·mysql·云计算·it
斤斤计较1 小时前
Docker 环境安装(2025最新版)
运维·docker·容器
小锋学长生活大爆炸1 小时前
【教程】Docker方式本地部署Overleaf
运维·docker·容器
xiaoyaoyou.xyz1 小时前
嵌入式Linux Qt开发:1、搭建基于ubuntu18.04的Qt开发环境及测试(解决Qt creator输入法问题)
linux·qt
Toky Zhu1 小时前
ubuntu清除缓存
linux·ubuntu·缓存
掘金者说1 小时前
docker系列-DockerDesktop报错信息(Windows Hypervisor is not present)
运维·docker·容器
影龙帝皖2 小时前
Linux服务之lvs集群与dr模式部署
linux·服务器·lvs
2302_799525742 小时前
【Linux】第十六章 分析和存储日志
linux·运维·服务器