二、IO学习总结

本文详细介绍了Linux/Unix下的IO学习,包括IO的分类、标准IO与文件IO的特性,如流、缓冲机制和文件操作。此外,还讨论了系统调用、文件流定位、空洞文件以及目录和文件属性的管理,最后提到了静态库和动态库的创建与使用。
摘要由CSDN通过智能技术生成

一、概论

(一)为什么要学习IO?

  1. 目的:为了将数据存储以及对于文件的操作
  2. 注意:
    文件:普通文件或者硬件设备(Linux下一切皆文件)
  3. Linux下的7种文件属性:
    (1)普通文件 -
    (2)目录文件 d
    (3)符号链接文件(软链接): l
    (4)字符设备文件:c
    (5)块设备文件 :b
    (6)管道文件:p
    (7)套接字文件:s

(二)IO的分类

第一类:标准IO(高级磁盘IO)

  1. ANSI(美国标准协会)联合ISO(国际化标准组织)所形成的的一个C标准(C标准:属于C库,含有一些列输入输出函数),只要操作系统支持C库,就可以使用这一类标准IO提供的函数(移植性比较高)。
  2. 操作的文件一般是普通文件。
  3. 属于高级磁盘IO。存在缓冲区,减少了用户态切换至内核态,最后又返回用户态这样的频繁操作,意味着减少了系统开销。
  4. 通过文件流(FILE *)操作文件(打开文件时,系统会自动将该文件的信息定义结构体类型struct FILE 来进行存储,因此可以通过FILE *文件指针来操作文件)

第二类:文件IO(低级磁盘IO)

  1. POSIX(可移植操作系统接口)推出的对于支持POSIX标准的系统可以操作文件的一系列函数(UNIX系统一般都会支持POSIX的标准)。移植性不高(只能应用于UNIX系统)
  2. 操作的文件可以普通文件或者设备文件(硬件)。
  3. 低级磁盘IO。没有缓冲区,每一次都是系统调用,都会存在用户空间和内核空间的频繁切换工作,好处就是可以直接对于设备进行读写操作。
  4. 通过文件描述符来(非负的数字)操作文件。

(三)系统调用和缓冲机制

在这里插入图片描述
注意:
库函数和系统调用函数的关系:大多数库函数都是由系统调用函数封装起来的。

二、标准IO

(一)流

  1. 概念:文件被打开时,创建的结构体名为FILE的结构体指针,形象的称为“流”。
  2. 分析:为啥称结构体指针为流?
    因为标准IO存在缓冲区,所以每一次向缓冲区不断放入数据(每一次的放入数据:均是需要通过文件指针来进行读写指向的文件),存在三个特点:
    (1)有源头:APP
    (2)有目的:缓冲区
    (3)持续性:不断放入数据到缓冲区
    一旦具备以上3个特点,就会形成流,所以通过文件指针操作文件可以理解为是通过操作流来操作文件。

(二)流的分类

文件被打开的时候,会默认具备3个类:

  1. stdin(标准输入:键盘) -->0
  2. stdout(标准输出:终端) -->1
  3. stderr(标准出错:会向终端打印,不带缓冲区(意味着每一次出错就会立即刷新缓冲区)) -->2

因此:当用户以后想要操作文件时,就需要先打开文件,此时会拥有一个文件流指针,以后通过该文件指针就可以操作文件。

(三)缓冲机制

  1. 全缓冲
    缓冲区被放满,程序结束,强制刷新:会引起缓冲区的刷新
  2. 行缓冲
    缓冲区被放满,程序结束,强制刷新,遇到换行符:会引起缓冲区的刷新
  3. 不带缓冲
    不存在缓冲区的概念:每一次读写都是直接输出:stderr

(1)缓冲区被放满:

#include <stdio.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
   
	while(1)
	{
   
		printf("hello");
		//延时函数
		sleep(1);
	}
	return 0;
}

此时处于不断向缓冲区放hello,延时时间为1秒钟1次,因此当缓冲区没有放满时,不会刷新缓冲区,也就看不到hello。

(2)程序结束:

#include <stdio.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
   
	printf("hello");
	return 0;
}

(3)强制刷新:

#include <stdio.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
   
	
	while(1)
	{
   
		printf("hello");
		sleep(1);
		//强制刷新
		fflush(stdout);
	}
	return 0;
}

一秒钟后再强制刷新输出流

(四)操作文件

1、流程

提供给用户来操作文件的方式有3种:
不管是哪种方式来操作文件,流程为:
(1)打开文件FILE *fopen(const char *path,const char *mode);

  • 参数1:需要打开文件的名字(可以包含路径,指针类型)
  • 参数2:打开文件的方式(指针类型)
  • 返回值:
    打开文件成功之后的文件流指针
    失败为NULL
    在这里插入图片描述
    打开文件代码如下:
#include <stdio.h>

int main(int argc, const char *argv[])
{
   
	//打开一个指定文件
	//char *FileName = "1.c";
	//char *Mode = "r";
	FILE *fr = fopen(argv[1],"r");
	//FILE *fr = fopen("2.c","r");
	//FILE *fr = fopen(FileName, Mode);
	//判断fr的值
	if(NULL == fr)
	{
   
		perror("fopen error");
		return -1;
	}
	printf("fopen_read ok!\n");
	//关闭文件
	fclose(fr);
	return 0;
}

(2)操作文件:读写文件
3种方法:按照字符操作、按照行操作、按照块操作

(3)关闭文件
头文件:#include <stdio.h>
函数原型:int fclose(FILE *stream);
因此:打开文件和关闭文件在标准IO下都是使用同一个接口,只是在操作文件的方式上存在选择.

2、按照字符操作

(1)函数名:fgetc() fputc
(2)头文件:#include <stdio.h>
(3)函数原型:

int fgetc(FILE *stream);

  • 功能:从指定的文件流中获取一个字符
  • 参数:指定获取一个字符所处文件的文件流
  • 返回值:
    成功返回获取到的字符值
    读取到文件末尾返回EOF(-1)
    操作中失败返回负数

int fputc(int c, FILE*stream);

  • 功能:向指定的文件流中输出一个字符
  • 参数:
    参数1:需要输出的指定字符(字符被称为单字节的整形)
    参数2:指定输出字符到的文件对应的文件流
  • 返回值:
    成功返回刚写入的字符值
    失败返回EOF(-1)

案例:
实现对于指定一个文件读取,读取方式为按照字符操作,将读取完毕之后的结果显示在终端上。(自己实现命令cat 文件名)
思路:
1、打开需要显示文件内容所在的文件
2、获取一个字符
3、输出一个字符
4、重复2、3直至文件末尾截止
5、关闭文件
代码:

#include <stdio.h>

//功能:实现命令cat的功能
int main(int argc, const char *argv[])
{
   
	//入参检查
	if(argc < 2)
	{
   
		printf("传参过少!\n");
		return -1;
	}
	
	//打开需要读取的文件
	FILE * fr = fopen(argv[1], "r");
	if(NULL == fr)
	{
   
		perror("fopen_read error");
	}
	printf("fopen_read success!\n");

	//借助于循环完成读取并显示
	while(1)
	{
   
		//读取
		char chr = fgetc(fr)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值