【Linux】基础IO

C标准库的文件IO接口

FILE * fopen(const char * path,const char * mode);

fopen函数为打开一个文件,path是要打开的文件名,mode则是打开文件的方式,返回类型为文件流指针,若打开失败则返回NULL
mode的几种形式:
 

r以只读方式打开文件,该文件必须存在
r+以读/写方式打开文件,该文件必须存在
w打开只写文件,若文件存在则文件长度清为零,即该文件内容会消失;若文件不存在则创建该文件
w+打开可读/写文件,若文件存在则文件长度清为零,即该文件内容会消失;若文件不存在则创建该文件
a以附加的方式打开只写文件。若文件不存在,则会创建该文件;如果文件存在,则写入的数据会被加到文件尾后,即文件原先的内容会被保留
a+以附加方式打开可读/写的文件。若文件不存在,则会创建该文件,如果文件存在,则写入的数据会被加到文件尾后,即文件原先的内容会被保留
size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream);

fwrite函数功能是向一个文件写入数据,成功返回实际写入的数据个数(小于或等于count)。buffer是一个指针,对fwrite来说,是要获取数据的地址。size为要写入内容的单字节数。count为要进行写入多少个size字节数。stream是目标文件的文件流指针。

size_t fread( void * buffer , size_t size , size_t count , FILE * stream );

fread从文件流中读数据,最多读取count个项,每个项size个字节,如果调用成功返回实际读取到的项个数(小于或等于count),如果不成功或读到文件末尾返回 0。

关闭文件fclose(FILE* stream);

 

系统调用的文件IO接口

open:

int open(const char *pathname,int flags,mode_t mode);
int open(const char *pathname,int flags);

open函数为系统调用,以指定方式打开一个文件,成功返回文件描述符,失败返回-1。pathname为要打开的文件名,flags为打开的方式,mode为文件权限(非必选项)
几种flags形式:
 

O_RDONLY只读打开
O_WRONLY只写打开
O_RDWR 读写打开
O_CREAT 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
O_APPEND追加写

write:

ssize_t write (int fd,const void * buf,size_t count);

write函数为系统调用,将buf指针指向的数据写入count个字节到fd文件描述符所代表的文件中。成功返回实际写入的字节数,失败返回-1。

read:

ssize_t read (int fd, void *buf, size_t count);

read将读取文件描述符fd所代表的文件,读取count个字节到buf中,成功返回实际读取到的字节数,失败或已经读到末尾则返回0。

关闭文件 close(int fd);

文件描述符

文件描述符就是从0开始的小整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file结构体。表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让进程和文件关联起来。每个进程都有一个指针*files, 指向一张表files_struct,该表最重要的部分就是包涵一个指针数组,每个元素都是一个指向打开文件的指针!所以,本质上,文件描述符就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件。

一个进程会默认打开三个文件描述符:0标准输入,1标准输出,2标准错误输出。
文件描述符的分配规则:在files_struct数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符。

文件重定向

< 标准输入重定向
> 标准输出重定向  清空原有内容后添加新内容
>> 标准输出重定向  向原有内容下方添加新内容

dup2系统调用:

int dup2(int oldfd,int newfd);
将newfd重定向到oldfd
dup2(fd,1)---将标准输出重定向到fd描述符(文件)。

C库函数和系统调用的一个重要区别

我们使用C标准库函数进行文件操作时,使用的是文件流指针FILE,因为库函数是对系统调用的封装,所以本质上都是通过文件描述符fd来访问文件。所以C库中的FILE结构体中,必定封装了文件描述符。

#include <stdio.h>
#include <string.h>
int main()
{
 const char *msg0="hello printf\n";
 const char *msg1="hello fwrite\n";
 const char *msg2="hello write\n";
 printf("%s", msg0);
 fwrite(msg1, strlen(msg0), 1, stdout);
 write(1, msg2, strlen(msg2));
 fork();
 return 0;
}

运行结果为:

hello printf
hello fwrite
hello write

我们将标准输出重定向的文件中,再来查看结果:

hello write
hello printf
hello fwrite
hello printf
hello fwrite

我们发现 printf 和 fwrite (库函数)都输出了2次,而 write 只输出了一次(系统调用)。

一般C库函数写入文件时是全缓冲的,而写入显示器是行缓冲。printf fwrite 库函数会自带缓冲区,当发生重定向到普通文件时,数据的缓冲方式由行缓冲变成了全缓冲。而我们放在缓冲区中的数据,就不会被立即刷新,甚至fork之后。
进程退出之后,会统一刷新,写入文件当中。但是fork的时候,父子数据会发生写时拷贝,所以当你父进程准备刷新的时候,子进程也就有了同样的一份数据,随即产生两份数据。write 没有变化,说明没有所谓的缓冲。

上面程序,当调用write时,因为没有自带缓冲区,数据被直接输出,而之后printf和fwrite都自带缓冲区,在fork之后才会刷新,子进程拷贝了父进程缓冲区数据。所以我们看到第一行输出了write,而后输出printf和fwrite。

<think>好的,我现在需要帮助用户了解Linux下的基础IO操作教程。根据用户提供的引用内容,我需要整合这些信息,并按照系统级指令的要求来组织回答。首先,用户提到引用了四个不同的来源,其中引用了Linux基础IO、进程控制、文件操作以及标准IO和系统调用IO的区别等内容。 首先,我需要确保回答结构清晰,分步骤解释Linux基础IO操作。根据引用[2],Linux中一切皆文件,包括标准输入输出和硬件外设,所以应该从文件描述符和文件操作的系统调用开始。然后,引用[3]和[4]提到了标准IO和系统调用IO的区别,需要详细说明两者的不同以及使用场景。用户可能对如何打开、读写文件,以及文件描述符的管理感兴趣。 接下来,按照系统级指令,所有行内数学表达式需要用$...$格式,但在这个问题中可能数学公式较少,更多是代码和命令。独立公式如果需要的话用$$...$$,不过可能这里不需要。需要检查LaTeX语法是否正确,使用中文回答,并生成相关问题。 然后,根据用户提供的引用内容,需要将相关知识组织成教程。例如,文件描述符的概念、系统调用如open、read、write、close的使用,标准库函数如fopen、fread、fwrite,以及两者的区别和选择。此外,可能需要提到文件权限、缓冲机制等。 还要注意引用标识的正确添加,例如在提到一切皆文件时引用[^2],在标准IO和系统调用IO的区别时引用[^3],在提到fwrite参数时引用[^4]。同时,用户的问题是关于基础IO操作的教程,因此需要涵盖基本操作步骤、常用函数和示例代码。 最后,生成相关问题,可能需要包括系统调用与标准库函数的比较、文件描述符的管理、缓冲机制的影响等。 现在需要将这些内容整合成一个结构清晰的中文回答,符合用户指定的格式,包括代码块和引用标注,最后生成相关问题列表。</think>### Linux 基础 IO 操作教程 #### 一、文件描述符与“一切皆文件”原理 在 Linux 中,所有硬件设备(如键盘、显示器)和软件资源(如普通文件)均被视为**文件对象**。操作系统通过统一的接口(读方法、写方法)驱动这些对象,并使用文件描述符(`fd`)进行管理。例如,标准输入(键盘)对应 `fd=0`,标准输出(显示器)对应 `fd=1`,标准错误对应 `fd=2`[^2]。 #### 二、系统调用 IO 操作 1. **打开文件** 使用 `open` 函数: ```c #include <fcntl.h> int fd = open("test.txt", O_RDWR | O_CREAT, 0644); // 权限模式 0644 ``` - 参数:文件名、标志位(如 `O_RDONLY` 只读)、权限 - 返回值:成功返回文件描述符,失败返回 -1 2. **读写文件** - `read` 函数: ```c ssize_t num = read(fd, buffer, sizeof(buffer)); // 返回实际读取字节数 ``` - `write` 函数: ```c ssize_t num = write(fd, "Hello", 5); // 返回实际写入字节数 ``` 3. **关闭文件** ```c close(fd); // 释放文件描述符 ``` #### 三、标准 IO 库函数 标准 IO(如 `fopen`)通过**用户空间缓冲区**提升效率,适合高频小数据操作[^3]。 1. **打开文件** ```c FILE* fp = fopen("test.txt", "r+"); // 模式包括 "r"(读)、"w"(写) ``` 2. **读写操作** - `fread`: ```c size_t count = fread(buffer, sizeof(char), 100, fp); // 读取100个char类型数据 ``` - `fwrite`: ```c fwrite("Data", 1, 4, fp); // 参数:数据指针、块大小、块数量、文件指针 ``` 3. **关闭文件** ```c fclose(fp); // 刷新缓冲区并关闭 ``` #### 四、系统调用 IO 与标准 IO 的选择 | **场景** | **推荐方法** | **原因** | |------------------------|-------------------|-----------------------------| | 高频小数据读写 | 标准 IO(如 `fprintf`) | 缓冲区减少系统调用次数 | | 直接访问硬件驱动程序 | 系统调用 IO | 绕过缓冲区,直接操作底层 | #### 五、关键概念解析 - **文件描述符表**:每个进程独立维护,通过 `fd` 索引内核中的文件对象。 - **缓冲机制**:标准 IO 的三种缓冲模式(全缓冲、行缓冲、无缓冲)通过 `setvbuf` 设置。 ```c // 示例:复制文件内容(系统调用 IO) #include <unistd.h> #include <fcntl.h> int main() { int src_fd = open("src.txt", O_RDONLY); int dest_fd = open("dest.txt", O_WRONLY | O_CREAT, 0644); char buf[1024]; ssize_t num; while ((num = read(src_fd, buf, sizeof(buf))) > 0) { write(dest_fd, buf, num); } close(src_fd); close(dest_fd); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值