Linux标准I/O

文章目录

  • linux-开发与管理 P9 标准I/O
    • 系统调用
      • 什么是系统调用?
      • 为什么要进行系统调用?
      • 为什么不直接访问计算机资源?
      • 系统调用了系统的哪些功能?
    • 用户程序编程接口(API)
      • 什么是API?
      • API的优势
      • POSIX标准
    • 标准I/O概述
      • 什么是标准I/O?
      • 流(stream)
    • 标准I/O编程
      • 流的打开与关闭
      • 流的读写
      • 错误处理
      • 流的定位
    • 更多内容

linux-开发与管理 P9 标准I/O

Linux标准I/O_第1张图片

系统调用

Linux标准I/O_第2张图片

什么是系统调用?

用户程序操作系统提出请求的接口称为系统调用

所有的操作系统都会提供系统调用接口,只不过不同的操作系统提供的系统调用接口各不相同。

Linux标准I/O_第3张图片

为什么要进行系统调用?

为了更好地服务于应用程序,因为操作系统负责管理和分配所有的计算机资源,所以操作系统提供了一组特殊的接口,通过这组接口,用户程序可以使用操作系统内核提供的各种功能,如分配内存创建进程实现进程之间的通信等。

为什么不直接访问计算机资源?

因为直接访问内存等资源是不安全的,当嵌入式系统有了操作系统之后,操作系统基本上都支持多任务,即同时可以运行多个程序,如果允许程序直接访问系统资源,肯定会带来很多问题;因此所有的软硬件资源的管理和分配都由操作系统负责,程序要获取资源必须通过操作系统来完成,即用户程序向操作系统发出服务请求,操作系统收到请求后执行相关的代码来处理。

系统调用了系统的哪些功能?

系统调用按照功能大致可分为进程控制进程间通信文件系统控制存储管理网络管理套接字控制用户管理等。

用户程序编程接口(API)

Linux标准I/O_第4张图片

什么是API?

API就是用户程序编程接口,通俗的解释就是各种库中的函数;
为了提高开发效率,C库中实现了很多函数,这些函数实现了常用的的功能,供调用所用;
API在实现时,通常都要依赖系统调用接口,很多API函数需要通过多个系统调用来完成其功能,还有一些API函数不需要调用任何系统调用。

API的优势

系统调用可以访问各种资源,但实际开发中程序并不直接使用系统调用接口,而是使用用户程序编程接口(API)

优点

  1. 系统调用口功能非常简单,无法满足程序的要求

  2. 不同操作系统的系统调用接口不兼容,程序移植时工作量大

  3. 而API程序具有良好的可移植性,几乎所有的操作系统上都实现了C库,所以程序通常只需要重新编译一下就可以在其他操作系统上运行。

POSIX标准

POSIX是用户程序编程接口(API)遵循了UNIX中最流行的应用编辑界面标准

POSIX标准是由IEEE和ISO/IEC共同开发的标准系统,该标准基于当时的UNIX实践和经验,描述了操作系统的系统调用编程接口,用于保证应用程序可以在源代码一级上在多种操作系统上移植运行,具有更好的可移植性。

标准I/O概述

Linux标准I/O_第5张图片

什么是标准I/O?

ANSI C中定义的用于I/O操作的一系列函数称为标准I/O

具有更好的可移植性,只要操作系统中安装了C库,标准I/O函数就可以调用,源代码不需要修改就可以在其他操作系统下编译运行。

标准I/O文件类型
常规文件 r
目录文件 d
字符设备文件 c
块设备文件 b
管道文件 p
套接字文件 s
符号链接文件 l

流(stream)

当用标准I/O打开一个文件时,就会创建一个FILE结构体描述文件,把这个创建的FILE结构体称为(stream),标准I/O都是基于流进行操作的。

流的缓冲类型

全缓冲:当填满标准I/O缓冲区后才进行实际I/O操作;标准I/O打开时是默认为全缓冲的,当缓冲区已满或执行flush操作时才会进行磁盘操作。
行缓冲:当在输入或输出中遇到换行符时执行I/O操作。
无缓冲:不对I/O操作进行缓冲,即在对流的读写时会立刻操作实际的文件。

文件与流的对比

文件:用一个结构体类型来存放打开的文件的相关信息
:文本流/二进制流

标准I/O预定义的三个流

流名称 编号 函数名 表示
标准输入流 0 STDIN_FILENO stdin
标准输出流 1 STDOUT_FILENO stdout
标准错误流 2 STDERR_FILENO stderr

标准I/O编程

Linux标准I/O_第6张图片

流的打开与关闭

流的打开(fopen())

所需头文件 #include
函数原型 FILE fopen(const char path,const char* mode)
函数参数 path:包含要打开的文件路径及文件名
mode:文件打开方式
函数返回值 成功:指向FILE的文件
失败:NULL

Mode的取值说明

r或rb 打开只读文件,该文件必须存在
r+或r+b 打开可读写的文件,该文件必须存在
w+或wb 打开只写文件,若文件存在则文件长度为0;若文件不存在则建立该文件(原先的内容不保留)
W+或w+b 打开可读写文件,若文件存在则文件长度为0;若文件不存在则建立该文件(原先的内容不保留)
a或ab 以附加的方式打开只写文件。若文件不存在,则会建立该文件;若果文件存在,写入的数据会被加到文件尾(原先的内容保留)
a+或a+b 以附加方式打开可读写的文件。若文件不存在,则会建立该文件;如果文件存在,写入的数据会被加到文件尾(原先内容保留)

文件权限

fopen()创建的文件访问权限是0666(rw-rw-rw-)

Linux系统中umask设定会影响文件的访问权限,其规则为(0666&~umask)

Root用户是022,普通用户是002

用户可以通过umask函数或者命令修改相关设定

举个栗子

Linux标准I/O_第7张图片

#include 

int main(int argc, const char *argv[])
{
	FILE *fp;
	if((fp = fopen("test.txt","r+")) == NULL){
		printf("fopen error\n");
		return -1;
	}
	return 0;
}

Linux标准I/O_第8张图片

流的关闭(fclose())

所需头文件 #include
函数原型 Int fclose(FILE *stream);
函数参数 Stream:已打开的流指针
函数返回值 成功:0
失败:EOF

举个栗子

Linux标准I/O_第9张图片

#include 

int main(int argc, const char *argv[])
{
	FILE *fp;
	fp = fopen("file.txt","w");

	fprintf(fp,"%s","hello cage!");
	fclose(fp);
	
	return 0;
}

Linux标准I/O_第10张图片

流的读写

字符输入

所需头文件 #include
函数原型 int getc(FILE *stream) ;
int fgetc(FILE *stream);
int getchar(void);
函数参数 Stream:要输入的文件流
函数返回值 成功:读取的字符
失败:EOF

字符输出

所需头文件 #include
函数原型 int putc(int c,FILE * stream);
int fputc(int c,FILE *stream);
int putchar(int c);
函数参数 Stream:要输入的文件流
函数返回值 成功:输出的字符
失败:EOF

举个栗子

Linux标准I/O_第11张图片

#include 

int main(int argc, const char *argv[])
{
	FILE *fp;
	int ch;

	fp = fopen("file.txt","w");
	for(ch = 1;ch <= 50;ch++){
		fputc(ch,fp);
	}
	fclose(fp);

	return 0;
}

Linux标准I/O_第12张图片

#include 

int main(int argc, const char *argv[])
{
	FILE *fp;
	int c;

	fp = fopen("file.txt","r");
	while(1){
		c = fgetc(fp);
		if(feof(fp)){
			break;
		}
		printf("%c",c);
	}
	fclose(fp);
	return 0;
}

Linux标准I/O_第13张图片

feof(测定流结束标识符)

检测当前文件是否检测到了结束的标识符

所需头文件 #include
函数原型 int feof(FILE *stream)
函数参数 Stream:要输入的文件流
函数返回值 成功:输出的字符
失败:EOF

按行输入

所需头文件 #include
函数原型 Char * gets(char *s);
Char * fgets(char *s,int size,FILE * stream);
函数参数 S:存放输入字符串的缓冲区首地址
Size:输入的字符串长度
Stream:对应的流
函数返回值 成功:返回s
失败:NULL

按行输出

所需头文件 #include
函数原型 Int puts(const char *s);
Int fputs(const char *s,FILE * stream);
函数参数 S:存放输出字符串的缓冲区首地址
Stream:对应的流
函数返回值 成功:s
失败: NULL

单位大小读文件

所需头文件 #include
函数原型 Size_t fread(void * ptr,size_t size,size_t nmemb,FILE *stream);
函数参数 Ptr:存放读入记录的缓冲区
Size:读取的每个记录的大小
Nmemb:读取的记录数
Stream:要读取的文件流
函数返回值 成功:返回实际读取到的nmemb数目
失败:EOF

单位大小写文件

所需头文件 #include
函数原型 Size_t fwrite(const void * ptr,size_t size,size_t nmemb,FILE *stream m);
函数参数 Ptr:存放写入记录的缓冲区
Size:写入的每个记录的大小
Nmemb:写入的记录数
Stream:要写入的文件流
函数返回值 成功:返回实际写入的nmemb数目
失败:EOF

举个栗子
Linux标准I/O_第14张图片

#include 
#include 

int main(int argc, const char *argv[])
{
	FILE *fp;
	char c[] = "fread and fwrite test";
	char buf[20];

	fp = fopen("file.txt","w+");
	fwrite(c,strlen(c)+1,1,fp);
	fseek(fp,0,SEEK_SET);

	fread(buf,strlen(c)+1,1,fp);
	printf("%s\n",buf);
	fclose(fp);

	return 0;
}

Linux标准I/O_第15张图片

fseek查找文件的开头


格式化输入

所需头文件 #include
函数原型 Int scanf(const char *format,…);
Int fscanf(FILE *fp,const char *format,…);
Int sscanf(char *buf,const char *format,…);
函数参数 Format:输入的格式
Fp:作为输入的流
Buf:作为输入的缓冲区
函数返回值 成功:输出字符数
失败:EOF

格式化输出

所需头文件 #include
函数原型 Int printf(const char *format,…);
Int fprintf(FILE *fp,const char *format,…);
Int sprintf(char *buf,const char *format,…);
函数参数 Format:输出的格式
Fp:作为输出的流
Buf:作为输出的缓冲区
函数返回值 成功:输出字符数
失败:EOF

错误处理

标准I/O函数执行时如果出现错误,会把错误码保存在全局变量errno中,可以通过相应的函数将错误打印出来。

perror函数

所需头文件 #include
函数原型 Void perror*(const char *s);
函数参数 S:在标准错误流上输出的信息
函数返回值

strerror函数

所需头文件 #include
#include
函数原型 Void *strerror(int errnum);
函数参数 错误码
函数返回值 错误码对应的错误信息

举个栗子
Linux标准I/O_第16张图片

#include 
#include 
#include 

extern int errno;

int main(int argc, const char *argv[])
{
	FILE *pf;
	int errnum;
	pf = fopen("file.txt","rb");
	if(pf == NULL){
		errnum = errno;
		fprintf(stderr,"错误号:%d\n",errno);
		perror("通过perror输出错误");
		fprintf(stderr,"打开文件错误:%s\n",strerror( errnum ));
	}else{
		fclose(pf);
	}
	return 0;
}

Linux标准I/O_第17张图片

流的定位

每个打开的流内部都有一个当前读写位置,流在打开时,当前读写位置为0,表示文件的开始位置。每读写一次后,当前读写位置自动增加实际读写的大小。在读写之间可先对流进行定位,即移动到指定的位置再操作。

移动到指定位置

所需头文件 #include
函数原型 Int fseek(FILE * stream,long offset,int whence);
函数参数 Stream:要定位的文件流
Offset:相对于基准值的偏移量
Whence:基准值 SEEK_SET:代表文件的起始位置 SEEK_END:代表文件结束位置 SEEK_CUR:代表文件当前读写位置
函数返回值 成功:0
失败:EOF

获取当前的定位

所需头文件 #include
函数原型 Long ftell(FILE * stream);
函数参数 Stream:要定位的文件流
函数返回值 成功:返回当前的读写位置
失败:EOF

举个栗子
Linux标准I/O_第18张图片

#include 

int main(int argc, const char *argv[])
{
	FILE *fp;
	fp = fopen("file.txt","w+");
	fputs("fseek just test now",fp);

	fseek(fp,6,SEEK_SET);
	fputs("C is Programming Langauge",fp);
	fclose(fp);

	return 0;
}

Linux标准I/O_第19张图片

更多内容

你可能感兴趣的:(嵌入式开发,Linux-开发与管理,嵌入式)