IO
IO概述:IO(Input/Output)是计算机系统中数据在不同实体间传输交互的抽象过程,涵盖了与外部设备(如文件、硬件、网络)的数据读写行为。本质上,它是程序与外部环境建立“数据通道”的核心机制,支撑着程序获取输入、输出结果的基本逻辑,是软件与硬件、本地与远程交互的底层依托;
IO作用:IO是程序与外部环境交互的基础桥梁。一方面,它为程序提供“输入”能力,支撑程序从文件、硬件、网络获取运行所需的数据(如游戏加载资源文件、程序读取用户输入);另一方面,通过“输出”功能,程序可能将计算结果持久化存储(如写入日志文件)、可视化展示(如输出到终端)或远程传输(如网络数据发送);

IO种类
按现实层级分类:
系统调用IO:也称之为文件IO,直接对接操作系统内核的最底层接口;逻辑极简、性能接近硬件,但是需要手动处理缓存区、错误码等细节;
库函数IO:也称之为标准IO,基于系统调用封装的高层接口;自动管理缓存区、跨平台兼容、简化开发,是用户态程序的常用选择;
按应用场景分类:
文件 IO:针对磁盘文件的读写(如日志记录、配置文件操作)。可通过“系统调用”或“库函数”实现;
设备IO:与硬件设备交互(如键盘输入、显示器输入)。操作系统通过“设备抽象”将设备转换为文件系统中的特殊文件,使程序能用统一的文件操作接口访问所有硬件,这正是Linux“一切皆文件”理念的核心;
网络IO:实现网络数据收发(如浏览器访问页面、APP通讯)。依赖系统调用或者是更高层的框架;
系统调用与库函数的区别

对比维度 系统调用 库函数
层级定位 操作系统内核提供的底层接口(如open) 基于系统调用/纯用户逻辑封装的高层工具(如C标准库fopen)
运行空间 运行于内核空间,需切换CPU特权级(用户态→内核态) 运行于用户空间,无需特权级切换
功能本质 直接操作硬件/内核资源(如读写磁盘、创建进程) 1.封装系统调用实现复杂功能(如printf调用write) 2.纯用户态逻辑(如strlen计算字符长度)
性能开销 因“用户态→内核态”切换,开销较大 1.若封装系统调用,开销略低(减少切换次数) 2.纯用户态函数开销极小
移植性 依赖操作系统内核 移植性差(如Linux与Windows系统调用不同) 跨平台苦逼(如C标准库),移植性好(同一函数适配多系统)

标准IO介绍
定义:标准I/O是C库提供的输入输出函数集合,由ANSI C 标准统一规范,为跨平台IO操作奠定基础;
跨平台性:在UNIX系统、Windows系统、Linux 等多系统操作均实现标准I/O库,让代码跨平台开发更顺畅;
高效实现原理:通过缓冲机制(内存临时存储数据),减少直接系统调用次数,降低硬件交互开销,提高IO效率;
易用性设计:基于系统底层调用封装,屏蔽复杂硬件操作,开发者无需关注设备细节,简单调用函数即可完成IO;

请添加图片描述

流(stream)
定义:所有I/O操作抽象为字节的“移入/移出”程序的过程,这种字节流动形态,称为流。
分类:
文件流:按字符编码(ASCII、UTF-8)处理,注意文本语义;
二进制流:直接操作原始字节,保留数据原始形态(如图片、可执行文件);
默认打开的流:
(1)stdin:标准输入流(如键盘输入)
(2)stdout:标准输出流(如屏幕打印)
(3)stderr:标准错误流(专用于输出错误信息)

FILE对象
定义:FILE对象是一个结构体,用于存储文件或流相关的所有状态信息(如文件描述符、缓冲区大小、缓冲区当前位置、文件结束标志符等等);
FILE对象与流对应关系:
每个流在内存中由一个FILE对象表示,通过FILE*指针访问;
标准流的特殊FILE对象:
(1)stdin:是标准输入流对应的FILE对象指针,通常关联到键盘输入;
(2)stdout:是标准输出流对应的FILE对象指针,通常关联到控制台输出;
(3)stderr:是标准错误流对应的FILE对象指针。通常关联到控制台,用于输出错误信息;

FILE对象
由于FILE对象通常较大且内部结构复杂,标准I/O函数不直接操作FILE对象本身,而是通过FILE指针(FILE*)来间接访问。FILE指针是指向FILE对象的内存地址,所有文件操作(如打开、读写、关闭)都基于这个指针进行;
FILE指针创建与销毁:通过fopen()进行创建FILE指针,通过fclose()进行销毁FILE指针;
FILE指针操作:所有标准I/O函数都以FILE指针作为参数,常见操作包括读写操作、定位操作、错误检查等等;
FILE对象与底层系统调用的关系:FILE对象是标准库层面的抽象,而Linux内核通过文件描述符(如0、1、2对应标准输入/输出/错误)管理文件。FILE对象内部维护了一个文件描述符吧,将标准I/O函数映射到底层系统调用(如read()、write()),并提供缓冲区优化;

标准IO的缓冲区
定义:标准I/O中的缓冲区是C语言标准库为 优化文件读写效率设计 的内存机制,本质上就是一段由FILE结构体管理的内存空间;
作用:通过临时存储数据、批量处理,可以减少硬件IO(如磁盘、终端)的交互次数,提示程序效率;
缓冲策略 :标准I/O中设计了行缓冲、全缓冲、无缓冲三种策略,来适配不同的场景,也支持手动修改;
行缓冲:默认用于终端设备(如stdout、stdin),Linux系统中行缓冲的大小为1024(1KB);
全缓冲:默认用于文件(如.txt),Linux系统中行缓冲的大小为4096(4KB);
无缓冲:不使用临时内存暂存,数据直接 写入硬件(如stder);无缓冲区的大小为0;

行缓冲刷新时机
(1)遇到换行符"n"会刷新缓冲区;
(2)程序正常结束会刷新缓冲区;
(3)当文件关闭时会刷新缓冲区;
(4)当输入和输出发生切换时会刷新缓冲区;
(5)缓冲区写满(未到换行符)会刷新缓冲区;
(6)主动调用fflush函数会强制刷新缓冲区;

fflush函数

所需头文件:#include <stdio.h>
原型:int fflush(FILE *stream);
功能:将指定流(stream)缓冲区中尚未写入的内容强制写入到对应的输出设备(如终端、文件等)中
参数:stream:用于指定需要刷新缓冲区的流
返回值:成功:返回0,刷新了流缓冲区
	   失败:返回EOF,并将error设置为具体的错误类型

全缓冲刷新时机
(1)程序正常结束会刷新缓冲区;
(2)当文件关闭时会刷新缓冲区;
(3)当输入和输出发生切换时会刷新缓冲区;
(4)缓冲区写满(未到换行符)会刷新缓冲区;
(5)主动调用fflush函数会强制刷新缓冲区;

手动设置缓冲
为什么需要手动设置缓冲?
(1)覆盖默认缓冲策略:不同系统/语言对IO流的默认缓冲设置不同(例如C语言中stdout默认行缓冲,stderr默认无缓冲),手动设置可按需调整;
(2)性能与实时性平衡:
①行缓冲:适合交互式输出(如命令行程序),每行输出后自动刷新;
②全缓冲:适合大量数据批量写入(如日志文件),减少IO次数
③无缓冲:适合需要立即 显示的关键信息(如错误日志)
(3)特殊场景需求:例如网络编程中避免数据堆积 ,或调试时强制输出中间结果;

手动设置缓冲区典型应用场景:
(1)日志系统:根据日志级别设置缓冲(错误日志无缓冲,普通日志全缓冲)
(2)交互式工具:命令行程序中确保用户输入后立即响应;
(3)嵌入式系统:受限内存环境下自定义缓冲区大小;

setbuf函数

所需头文件:#include <stdio.h>
原型:void setbuf(FILE *stream, char *buf);
功能:设置指定文件流的缓冲区
参数:stream:指向FILE对象的指针,标识要设置缓冲区的文件流
	 buf:指向用户提供的缓冲区的指针
		  如果提供了缓冲区,其大小必须至少为BUFSIZ字节(通常在stdio.h中定义)
		  如果是NULL,则是无缓冲模式
返回值:无

setbuf函数允许两种方式的缓冲:
全缓冲;如果buf指向一个大小大于0的缓冲区,那么IO操作将使用全缓冲模式
无缓冲:如果buf为NULL,或者是大小为0,那么IO操作将会变为无缓冲模式;,
setbuf函数注意事项:
(1)调用setbuf函数应该在打开文件流或者是任何IO操作之前,否则可能不会生效;
(2)如果要使用自定义的缓冲区,确保缓冲区足够大,以避免缓冲区溢出;
(3)当使用自定义缓冲区时,不要在buf指向的缓冲区被释放后再进行IO操作,以免导致未定义的行为;

sleep函数

所需头文件:#include <unistd.h>
原型:unsigned int sleep(unsigned int seconds);
功能:用于让程序暂停执行指定的时间
参数:seconds:指定程序暂停执行的秒数
返回值:成功返回0;失败若程序被信号中断,返回未休眠的秒数

setvbuf函数

所需头文件:#include <stdio.h>
原型:int setvbuf(FILE *stream, char *buf, int mode, size_t size);
功能:更加灵活地控制文件流的缓冲行为,允许指定缓冲模式和缓冲区的大小
	 该函数必须在对stream执行任何其他操作前调用
参数:stream:指向FILE对象的指针,标识要设置缓冲区的文件流
     buf:指向用户提供的缓冲区的指针
		 如果为NULL,函数会自动分配一个大小为size的缓冲区
     mode:缓冲区模式填写以下宏:
         _IOFBF: fully buffered             全缓存
         _IOLBF: line buffered              行缓存
         _IONBF: unbuffered                 无缓存
		当mode为_IONBF时,size参数被忽略
     size:缓冲区的大小(以字节为单位)
返回值:成功返回0,失败返回非0值
练习:如何将行缓存设置为全缓存

setvbuf函数注意事项:
(1)setvbuf必须在文件流执行任何读写操作之前调用,文件流初始化后,否则可能导致设置失败,或触发未定义行为;
(2)若使用自定义缓冲区(buf != NULL),需确保缓冲区大小size与实际需求匹配。若size过小,可能导致数据溢出;若size过大,会浪费内存资源;
(3)若使用自动分配缓冲区(buf = NULL),size需设置合理值(通常建议不小于系统默认缓冲区大小,如BUFSIZ),避免因缓冲区过小影响性能或触发溢出;
(4)禁止在缓冲区被释放后对文件流执行IO操作,否则会触发未定义行为(如访问已释放内存导致崩溃);
(5)当mode为_IONBF(无缓冲)时,size参数会被忽略(即使设置非零值也无效),需避免依赖size配置无缓冲模式;
(6)不同系统对mode的支持可能有差异(如某些嵌入式环境可能不支持行缓冲_IOLBF),需要根据实际平台验证行为;

标准IO
1.提高程序的可移植性
2.减少系统调用次数,提高系统效率
缓存
行缓存1024
刷新缓冲区的条件
1.回车,2.程序结束,3.强行刷新fflush,4.缓存区满
练习:刷新行缓存的条件
全缓存4096
1.程序结束,2.强制刷新,3.缓存区满
无缓存
标准错误输出是无缓存;

练习:
计算行缓存的大小(利用结构体)

man手册使用方式
man手册是用于在linux系统中查询命令、函数等的帮助手册,不同的章节分类便于快速定位获取各类;linux系统相关的帮助信息;
以下是一些常用用法:
man man:查看man手册自身的章节说明,了解man手册整体架构和使用规范;
man 1 要查看的内容:查看可执行程序或shell命令的帮助文档,“1”对应用户命令章节;
man 2 要查看的内容:查看系统调用(内核提供的函数)相关帮助,“2”对应系统调节章节;
man 3 要查看的内容:查看库调用(库中的函数),“3”对应库函数章节;

内核中错误码的问题
在Linux系统中,内核通过预定义宏(如ENOENT)标识错误,错误码为正整数,内核返回时用负数传递;
错误码转换为错误信息-strerror函数

所需头文件:#include <string.h>
原型:char *strerror(int errnum);
功能:将错误码转换为错误信息
参数:errnum:错误码
返回值:成功返回指向错误信息的字符串指针
	   若errnum无效:返回结果由系统实现决定(通常返回通用错误描述,如"Unknown error nnn"

错误信息打印函数=perror函数

所需头文件:#include <stdio.h>
原型:void perror(const char *s);
功能:打印错误信息
	 如果s不为NULL*s不为空字节('\0'),则打印参数字符串s,后跟一个冒号和一个空格;
	 然后打印与当前error值对应的错误消息和一个换行符;
参数:s:用户的附加信息
	    若s非空(s != NULL && *s != '\0'),则输出s:(字符串+冒号+空格)
		若s为空(s == NULL || *s == '\0'),则不同系统可能输出":错误信息"或直接输出"错误信息"
返回值:无

对文件操作的步骤
1、打开文件

所需头文件:#include <stdio.h>
函数原型:FILE *fopen(const char *pathname, const char *mode);
功能:用标准IO的方式打开文件
返回值:成功返回FILE指针;失败返回NULL,重置错误码
参数:
	pathname:文件路径和名字,不写路径默认打开当前路径下的文件
    mode:打开文件的方式
    r:以只读的方式打开文件,将光标定位到文件开头,如果文件不存在则会报错
    r+:以读写的方式打开文件,将光标定位到文件开头,如果文件不存在则会报错
    w:以只写方式打开文件,如果文件存在就清空;如果文件不存在就创建,将光标定位到开头
    w+:以读写方式打开文件,如果文件存在则清空;如果文件不存在则创建,将光标定位到结尾
    a:以追加的方式打开文件,如果文件不存在则创建;如果文件存在不会清空,将光标定位到结尾
    a+:以读和追加的方式打开文件,如果文件不存在就创建;如果文件存在不会清空
		如果读操作光标在文件开头;如果写操作总是在文件结尾;
    
练习:
    1、使用fgetc完成对文件的读取
    2、通过不同的权限创建文件
    3、模拟cp命令的实现

2、读文件内容

1、fgetc函数
所需头文件:#include <stdio.h>
原型:int fgetc(FILE *stream);
功能:从文件流中读取当前位置的字符
	 每次调用fgetc会自动移动文件指针,指向下一个字符位置,为后续读取做准备
参数:stream:文件指针
返回值:成功返回无符号字符(unsigned char)的数值(范围0~255),并转换为int返回
	   若返回char255(unsigned char)会被视为-1(signed char),EOF冲突
	   失败或读到文件末尾返回EOF-12、fgets函数
所需头文件:#include <stdio.h>
原型:char *fgets(char *s, int size, FILE *stream);
功能:在文件stream中读取字符串,将读取的内容存储到由s指向的缓冲区中
	 最多读取size-1个字符(含可能的换行符\n),读取完成后会自动在缓冲区末尾补充字符串结束符\0
	 fgets遇到文件结束符(EOF)或换行符(\n)时停止,换行符也会被一同存储到s中
参数:s:用于存放读到的内容的内存首地址
	 size:想要读取的字节数
	 stream:文件指针
返回值:读取成功返回字符串s;读取失败或者是读取到文件结束返回NULL
3、fread函数
所需头文件:#include <stdio.h>
原型:size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:从stream中读取nmemb项数据,每项大小为size,将它们存入ptr指向的位置中
参数: ptr:存储读到的数据首地址
      size:每个数据项的大小(单位是字节)
			一般将其置为1,让项目数表示字节数
      nmemb:要读取的数据项的最大数量
      stream:文件指针
返回值:成功返回实际读取的数据项数量
	   返回值小于nmemb时,可能是遇到了文件结束(EOF)或者是出现了错误
	   返回值为0,就是没有读取到任何的数据
fread不区分文件结束(EOF)或者是读取错误,调用者必须使用feof函数或者ferror函数来区分场景

3、写入

1、fputc函数
所需头文件:#include <stdio.h>
原型:int fputc(int c, FILE *stream);
功能:向文件中写入一个字符
参数:c:要写入的字符
	 stream:文件指针
返回值:成功返回写入的字符的ASCII码;失败返回EOF
2、fputs函数
所需头文件:#include <stdio.h>
原型:int fputs(const char *s, FILE *stream);
功能:将字符串s的内容写到stream指向的文件中,仅写入字符串有效字符(不包含末尾\0)
参数:s:要写入字符串的首地址
	 stream:文件指针
返回值:成功返回非负整数;失败返回EOF-13、fwrite函数
所需头文件:#include <stdio.h>
原型:size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:按类型进行数据写入
参数: ptr:指向要写入数据的内存首地址
      size:每个数据项的大小(单位是字节)
			一般将其置为1,让项目数表示字节数
      nmemb:要写入的数据项的最大数量
      stream:文件指针
返回值:成功返回实际写入的数据项数量
	   返回值小于nmemb时,可能是写入错误或到达文件末尾
 使用按类型写入的方式实现cp命令;

4、关闭文件

‍所需头文件:#include <stdio.h>
原型:int fclose(FILE *stream);
功能:用标准IO的方式关闭文件
参数:stream:文件指针
返回值:成功返回0;失败返回EOF(-1),重置错误码 

5.文件流指针的偏移

1. fseek函数
所需头文件:
原型:int fseek(FILE *stream, long offset, int whence);
函数功能:设置光标的位置
参数:stream:文件指针
   offset:光标的偏移
		   >0:向后偏移
		   =0:不偏移
		   <0:向前偏移
   whencs:从哪个位置偏移
		   SEEK_SET:从开头开始偏移
   		   SEEK_END:从当前位置偏移
		   SEEK_CUR:从结尾的位置偏移
返回值:成功:返回0
	   失败:返回-1,并设置为相应的错误码
练习:实现对图片的加密操作
2.rewind函数
所需头文件:#include <stdio.h>
原型:void rewind(FILE *stream);
功能:将光标恢复到文件的开头
参数:stream:文件指针
返回值:无
3. ftell函数
所需头文件:#include <stdio.h>
原型:long ftell(FILE *stream);
功能:返回文件流当前位置相对于文件起始位置的偏移量(以字节为单位)
参数:stream:文件指针
返回值:成功:返回字节数
	   失败:返回-1,并设置为相应的错误码

文件 IO
定义:文件IO是在POSIX(可移植操作系统接口)中定义的一组输入输出的函数,涉及操作系统和应用程序之间的交互,用于读取和写入存储在永久性存储介质(如硬盘、SSD、USB闪存盘等)上的数据;
跨平台性:不同的操作系统(如UNIX、Windows、Linux)的文件IO机制存在差异,接口、调用方式和底层实现逻辑各有特点;
如Windows下有CreateFile等专属函数,Linux则基于open、read等系统调用;
高效实现原理:
1.直接交互硬件/文件系统:绕过高级缓冲,直接发起系统调用
2.无用户态缓冲:不依赖用户态缓冲机制,每次读写更贴近硬件真实操作,但频繁调用会增加系统开销,需开发者按需优化(如手动合并读写请求);
易用性设计:
1.贴近底层逻辑:需开发者熟悉操作系统API、文件权限、设备特性等,直接处理缓冲区管理、错误码解析(Linux中errno),对开发经验要求高;
2.灵活但复杂:可精准控制文件打开模式(只读、读写等)、数据传输细节,却也因需手动处理资源释放(如close函数)、并发冲突等问题,增加开发复杂度;
特点:
1.没有缓冲机制,每次调用都会引起系统调用;
2.围绕文件描述符进行操作,相当于标准IO中的流(FILE*),文件描述符是正数;
3.默认打开三个描述符:标准输入(0) 标准输出(1) 错误输出(2)
4.除目录文件,其他类型文件都可以操作;
5.可移植性相对较弱;

对比维度 文件IO 标准IO
概念 对文件系统中的文件进行读写 程序与终端(控制台)交互
用途 持续化存储、跨程序数据交换 即时交互、简单调试
操作对象 磁盘文件(需路径或描述符) 以流为抽象,覆盖终端和磁盘文件
数据流向 程序⇄磁盘(持久化) 程序⇄终端(临时交互)
缓冲机制 默认缓冲 stdout:行缓冲 stderr:无缓冲
错误处理 需显式处理文件不存在、权限不足等 通常无需特殊处理(终端直接反馈)
典型场景 配置文件读写、日志记录、数据存储等 命令行参数输入、结果显示、错误提示等等
性能特点 大文件或批量读写,文件IO通过手动优化(调整读写块大小) 频繁小数据读写时,标准IO的缓冲机制更高效
生命周期 数据持久保存 会话结束后数据丢失

文件描述符
定义:文件描述符 是操作系统内核为每个打开的文件/设备分配的唯一整数标识符,用于标识和跟踪进程与文件的交互,在Linux/Unix中,它是底层文件IO操作的核心参数;
本质:
1.它是指向内核中维护的文件表(File Table),该表中记录了文件的状态,位置指针等信息;
2.每个进程都有自己独立的文件描述符表,通常是从0开始编号,相互不干扰;Linux系统中一个正在执行的程序中文件描述符的范围是[0-1023],可通过ulimit调整,一般使用默认值 ;
作用:
1.连接用户进程与内核资源:通过文件描述符,进程可以请求内核进行文件读写、设备操作等,无需关心底层实现细节;
2.资源管理:操作系统通过文件描述符跟踪哪些文件被哪些进程打开,并在进程关闭文件或退出时自动回收资源;
特点:
1.唯一性:同一个进程内,每个文件描述符对应唯一的打开文件;
2.非负数整数:通常是小整数(如0、1、2),但可动态分配(如open()返回的新描述符);
3.跨函数传递:可在不同系统调用间传递,代表对同一文件的持续操作;

常见文件描述符编号:

编号 宏定义 用途 对应设备
0 STDIN_FILENO 标准输入(Standard Input) 通常是键盘
1 STDOUT_FILENO 标准输出(Standard Output) 通常是终端屏幕
2 STDERR_FILENO 标准错误(Standard Error) 通常是终端屏幕

打开文件时,会默认打开三个文件描述符
分别是
输入 0
输出 1
错误输出 2
特点
适用于Linux或Unix操作系统,在用户空间无缓存,
用途
用于驱动开发无标准库提供的场景

对文件的操作
1、打开文件

所需头文件:#include <sys/types.h>
      	  #include <sys/stat.h>
     	  #include <fcntl.h>
原型:int open(const char *pathname, int flags);
	 int open(const char *pathname, int flags, mode_t mode);
功能:用文件IO的方式打开文件
参数:pathname:文件路径和名字
			  不写路径默认打开当前路径下的文件
     flags:打开文件的方式
     	O_CREAT:文件不存在则创建文件  
	 	如果flags中填写了O_CREAT,就必须填写第三个参数,第三个参数代表创建文件的权限 
	 	O_EXCL:只能与O_CREAT连用,如果文件不存在则创建;如果文件存在则报错,错误码为EEXIST
     	O_RDONLY:以只读方式打开文件,文件不存在则打开失败
     	O_WRONLY:以只写方式打开文件,文件不存在则打开失败
     	O_TRUNC:如果文件存在就清空
     	O_APPEND:以追加方式打开文件,文件不存在则打开失败
     	O_RDWR:以读写方式打开文件,文件不存在则打开失败
     mode:创建文件的权限,一般用8进制表示
		   实际创建出来的文件权限=(mode & ~umask)
		   O_CREAT存在时会设置文件创建的权限,通常填0666
		   umask:文件的掩码,通过umask命令可以查看掩码的默认值是0002
		   ~umask:文件掩码的取反是在最大的文件权限的基础上进行取反,最大文件的权限是0666
		   实际创建出来的文件权限=(0666 & ~(0002))=(0666 & 0664) = 0664
     r:O_RDONLY
     r+:O_RDWR
     w:O_WRONLY | O_CREAT | O_TRUNC 
     w+:O_CREAT | O_TRUNC | O_RDWR
     a:O_APPEND | O_CREAT | O_RDONLY
     a+:O_APPEND | O_CREAT | O_RDWR
返回值:成功返回文件描述符;失败返回-1,错误码errno会被正确设置

标准IO和文件IO打开方式对比

文件IO 标准IO 功能
O_RDONLY “r” 以只读的方式打开文件,将光标定位到文件开头
O_RDWR “r+” 以读写的方式打开文件,将光标定位到文件开头
O_WRONLY | O_CREAT | O_TRUNC,0666 “w” 以只写方式打开文件,如果文件存在就清空;如果文件不存在就创建,将光标定位到开头
O_CREAT | O_TRUNC | O_RDWR,0666 “w+” 以读写方式打开文件,如果文件存在则清空;如果文件不存在则创建,将光标定位到结尾
O_APPEND | O_CREAT | O_RDONLY,0666 “a” 以追加的方式打开文件,如果文件不存在则创建;如果文件存在不会清空,将光标定位到结尾
O_APPEND | O_CREAT | O_RDWR,0666 “a+” 以读和追加的方式打开文件,如果文件不存在就创建; 如果文件存在读光标始终在开头,写光标始终在结尾

2、对文件进行读写

1.read函数
所需头文件:#include <unistd.h>
原型:ssize_t read(int fd, void *buf, size_t count);
功能:用文件IO的方式读取文件中的内容
参数:fd:文件描述符
     buf:存储读取到的数据的首地址
     count:期望读取的字节数
返回值:成功返回读取到的字节数,读到文件末尾返回0;失败返回-1,错误码errno会被正确设置
2. write函数   
所需头文件:#include <unistd.h>
原型:ssize_t write(int fd, const void *buf, size_t count); 
功能:用文件IO的方式往文件中写入内容
参数:fd:文件描述符
     buf:想要写入数据的首地址
     count:期望写入的字节数
返回值:成功返回写入的字节数,返回0表示不会写任何的数据;失败返回-1,错误码errno会被正确设置
    
    
练习:1、查询man手册找到上述两个函数的参数返回值
     2、使用文件io实现cp命令

3、偏移:

所需头文件:#include <sys/types.h>
          #include <unistd.h>
原型:off_t lseek(int fd, off_t offset, int whence);
功能:定位光标的位置(光标实际指文件偏移量)
参数:fd:文件描述符
     offset:偏移量,向左负数 向右正数
     whencs:SEEK_SET   放在文件头
          SEEK_END 放在文件尾
          SEEK_CUR 当前指针位置 
返回值:        
        练习:使用文件io实现对图片的加密,(取前十个字节数据进行逆序)

4、关闭文件

所需头文件:#include <unistd.h>
原型:int close(int fd);
功能:用文件IO的方式关闭文件
参数:fd:文件描述符
返回值:成功返回0;失败返回-1,错误码errno会被正确设置

目录操作

1、打开目录
DIR *opendir(const char *name);
功能:打开目录
返回值:目录流指针
    参数:目录名 通常使用命令行参数argv[]
2、读目录的内容
struct dirent *readdir(DIR *dirp);
功能:读取目录内容;
返回值:
    成功:返回目录下一个文件的struct dirent结构首地址,读到结尾,返回NULL
	失败:返回NULL,并置errno
参数:dirp,目录流指针
    struct dirent *类型的结构体内容
    struct dirent {
               ino_t          d_ino;      
               off_t          d_off;       
               unsigned short d_reclen;   
               unsigned char  d_type;                               
               char           d_name[256]; 
           };
3、关闭目录
    int closedir(DIR *dirp);
功能:关闭目录;
返回值:成功返回0,失败返回-1
参数:dirp,目录流指针
    
练习:
 模拟ls命令的实现
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐