用户程序向操作系统提出请求的接口称为系统调用。
所有的操作系统都会提供系统调用接口,只不过不同的操作系统提供的系统调用接口各不相同。
为了更好地服务于应用程序,因为操作系统负责管理和分配所有的计算机资源,所以操作系统提供了一组特殊的接口,通过这组接口,用户程序可以使用操作系统内核提供的各种功能,如分配内存、创建进程、实现进程之间的通信等。
因为直接访问内存等资源是不安全的,当嵌入式系统有了操作系统之后,操作系统基本上都支持多任务,即同时可以运行多个程序,如果允许程序直接访问系统资源,肯定会带来很多问题;因此所有的软硬件资源的管理和分配都由操作系统负责,程序要获取资源必须通过操作系统来完成,即用户程序向操作系统发出服务请求,操作系统收到请求后执行相关的代码来处理。
系统调用按照功能大致可分为进程控制、进程间通信、文件系统控制、存储管理、网络管理、套接字控制、用户管理等。
API就是用户程序编程接口,通俗的解释就是各种库中的函数;
为了提高开发效率,C库中实现了很多函数,这些函数实现了常用的的功能,供调用所用;
API在实现时,通常都要依赖系统调用接口,很多API函数需要通过多个系统调用来完成其功能,还有一些API函数不需要调用任何系统调用。
系统调用可以访问各种资源,但实际开发中程序并不直接使用系统调用接口,而是使用用户程序编程接口(API)
优点
系统调用口功能非常简单,无法满足程序的要求
不同操作系统的系统调用接口不兼容,程序移植时工作量大
而API程序具有良好的可移植性,几乎所有的操作系统上都实现了C库,所以程序通常只需要重新编译一下就可以在其他操作系统上运行。
POSIX是用户程序编程接口(API)遵循了UNIX中最流行的应用编辑界面标准。
POSIX标准是由IEEE和ISO/IEC共同开发的标准系统,该标准基于当时的UNIX实践和经验,描述了操作系统的系统调用编程接口,用于保证应用程序可以在源代码一级上在多种操作系统上移植运行,具有更好的可移植性。
ANSI C中定义的用于I/O操作的一系列函数称为标准I/O。
具有更好的可移植性,只要操作系统中安装了C库,标准I/O函数就可以调用,源代码不需要修改就可以在其他操作系统下编译运行。
标准I/O文件类型
常规文件 r
目录文件 d
字符设备文件 c
块设备文件 b
管道文件 p
套接字文件 s
符号链接文件 l
当用标准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 |
流的打开(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函数或者命令修改相关设定
举个栗子
#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;
}
流的关闭(fclose())
所需头文件 | #include |
---|---|
函数原型 | Int fclose(FILE *stream); |
函数参数 | Stream:已打开的流指针 |
函数返回值 | 成功:0 |
失败:EOF |
举个栗子
#include
int main(int argc, const char *argv[])
{
FILE *fp;
fp = fopen("file.txt","w");
fprintf(fp,"%s","hello cage!");
fclose(fp);
return 0;
}
字符输入
所需头文件 | #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 |
举个栗子
#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;
}
#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;
}
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 |
#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;
}
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); |
函数参数 | 错误码 |
函数返回值 | 错误码对应的错误信息 |
#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;
}
每个打开的流内部都有一个当前读写位置,流在打开时,当前读写位置为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 |
#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;
}