首先声明下,写这些内容,是想检测下自己对高编的理解,函数的使用,记忆等方面的检测(当然有些内容还是来自于《UNIX高级编程》这本书);同时,也是想和大家分享些自己整理的知识,希望对那些和自己一样刚开始接触高级编程的朋友有所帮助。如有不妥的地方大家多多指教,我会第一时间改正,向大家学习。
说标准i/o之前先将下关于与之相关的的一些概念的定义。
系统调用:每个操作系统都在内核里有一些内建的函数库,这些函数可以用来完成一些系统系统调用把应用程序的请求传给内核,调用相应的的内核函数完成所需的处理,将处理结果返回给应用程序,这些函数集合起来就叫做程序接口或应用编程接口API接口;说白了其实质就是在用户层和内核层之间封装的一些函数库即前面所说的API。
而在实际的使用中,很少直接使用系统调用,而是使用标准I/O库函数;即在系统调用的基础上,又封装的一层;图一是简化的示意图,非专业词语描述;
标准I/O优点:带缓存(合并系统调用)
缺点:实时性低;
简化模型
标准I/O库的缓存机制,大大减少了对于函数read()和write()的操作,提高了效率;它的缓存机制又分为三种情况:
《1》 全缓存:该类型缓冲区要求填满整个缓冲区后才进行I/O操作,对于磁盘文件常使用全缓冲区访问。
《2》 行缓存:该类型缓冲区要求填满整个缓冲区后才进行I/O操作,对于磁盘文件常使用全缓冲区访问。行缓冲区:在该种模式下,当在输入和输出中遇到换行符时,标准I/O库执行I/O系统调用操作。当流涉及到一个终端时,使用行缓冲区。 因为标准I/O库收集的每行的缓冲区长度为固定的,只要填满缓冲区,即使还没有遇到换行符,也将执行I/O系统调用。 默认行缓冲区大小为128字节
《3》 无缓存 :主要对于实时性要求高的比如:错误输出
流:即打开文件的标识;类型为:
结构体类型(FILE *):
文件描述符
缓存区的地址
缓存的大小
出错标志
流的使用是一个很重要的概念,由于在LINUX系统中一切皆文件,而对于文件的操作和流又有很重要的密切关系,只因对于文件的操作起于它。当我们执行一个程序的时候实际上系统默认打开了三个流:标准输入,标准输出,标准错误;
下面具体讲一些关于标准I/O操作常用的函数:
(1)文件的打开
头文件 | #include <stdio.h> |
函数 | FILE *fopen(const char *path, const char *mode); FILE *fdopen(int fd, const char *mode); FILE *freopen(const char *path, const char *mode, FILE *stream); |
功能说明 | Fopen ()用来打开一个指定的文件;path 指文件的名,mode文件的权限设置; Fdopen()打开一个指定的文件,只是他是以文件描述符的形式打开,其他和fopen()一样 freopen用来在一个特定的流上打开一个特定的文件,当调freopen时,首先关闭stream流,然后重新使用这个FILE结构指针stream打开pathname所代表的文件,此函数常用来对标准输入、标准输出、标准错误输出等预定义的流进行重定向。 |
参数说明 | Mode:对应的模式分为: R:读文件只有读的权限;FILE *指向文件的其实位置 R+:读文件有读写权限;FILE *指向文件的其实位置 W:对文件有写的权限;文件存在则将其截断为零,不存在则创建; FILE *指向文件的其实位置 W+:对文件有读写的权限;文件存在则将其截断为零,不存在则创建; FILE *指向文件的其实位置 A: FILE *指向文件的其实位置,从文件的末端继续追加,具有写权限 A+: FILE *指向文件的其实位置,从文件的末端继续追加,具有读写权限 |
(2)Linux下的错误的捕捉:errno(全局变量)
error是一个全局变量,定义在(下图1仅仅是截取其中的一部分)
/usr/include/asm-generic/errno-base.h
/usr/include/asm-generic/errno.h
(a)与errno相关的常用函数有两个:
strerror(3);
perror(3);
头文件 | #include <string.h> |
函数 | char *strerror(int errnum); |
功能说明 | 依据errnum来查找与其对应错误原因描述字符串,并将该字符串指针地址返回;使用时需要定义一个字符型指针去接该地址 |
参数说明 | Errnum:错误码 |
头文件 | #include <stdio.h> #include<stdlib.h> #include <errno.h> |
函数 | void perror(const char *s); |
功能说明 | 用 来 将 上 一 个 函 数 发 生 错 误 的 原 因 输 出 到 标 准 设备 (stderr); 参数 s 所指的字符串会先打印出,后面再加上错误原因字符串。 此错误原因依照全局变量errno 的值来决定要输出的字符串。 |
参数说明 | S: 用户自定义字符串 |
(3)流的操作
(a)字节操作
头文件 | #include <stdio.h> |
函数 | int fgetc(FILE *stream); int fputc(int c, FILE *stream); |
功能说明 | Fgetc():参数stream 所指的文件中读取一个字符.,并返以整型数的形式返回。 若读到文件尾而无数据时便返回EOF. Fputc():将参数c以字符的形式写入到,stream所指向的文件中; |
参数说明 | Stream:文件流;c:字符 |
头文件 | #include <stdio.h> |
函数 | getc(FILE *stream); putc(int c, FILE *stream); |
功能说明 | getc():参数stream 所指的文件中读取一个字符.,执行成功返回读取到的字符。 若读到文件尾而无数据时便返回EOF. 但在某些库中getc()为宏定义,而非真正的函数。 putc():输入一个字符到指定流中,若正确,返回输入的的字符,否则返回EOF |
参数说明 | Stream:文件流;c:字符 |
头文件 | #include <stdio.h> |
函数 | int getchar(void); int putchar(int c); |
功能说明 | getc():从标准输入stdio中读取一个字符 putc():向stdout输出一个字符 |
参数说明 | Getchar:有一个int型的返回值.当用户键入回车之后,getchar才开始从stdin流中每次读入一个字符.getchar函数的返回值是用户输入的第一个字符的ASCII码,如出错返回-1,且将用户输入的字符回显到屏幕.如用户在按回车之前输入了不止一个字符,其他字符会保留在键盘缓存区中,等待后续getchar调用读取. |
(b)行操作
头文件 | #include <stdio.h> |
函数 | char *fgets(char *s, int size, FILE *stream); int fputs(const char *s, FILE *stream); |
功能说明 | Fgets:从文件stream中读取字符到s所指向的缓冲区中,最后一个字节被’\0’填充;成功,则返回第一个参数buf地址;错误,error指示器被设置,返回NULL Fputs: 将字符串写入指定的流,但不包括空字符; 返回一个非负的值,否则,错误返回EOF。 |
参数说明 | S:指向缓冲区,stream:文件流 |
头文件 | #include <stdio.h> |
函数 | char *gets(char *s); int puts(const char *s); |
功能说明 | gets: 从流中读取字符串,直到出现换行符或读到文件尾为止,最后加上NULL作为字符串结束。 puts:将s所指向的字符串写到标准输出 |
参数说明 | S:指向缓冲区, |
(c)二进制操作
头文件 | #include <stdio.h> |
函数 | size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); |
功能说明 | fread:从指向stream的流读取nmemb个size大小的数据到缓冲区ptr中 fwrite: 将缓冲区ptr中nmemb个size大小的数据写到stream所指向的文件中 两个函数操作成功均返回读/写的字节个数,错误返回0 |
参数说明 | ptr为存储要读取数据的缓冲区,size 为读取记录的大小,nmemb是所读取记录的个数,stream为所要读取的流的文件FILE指针 |
(d)格式换化
头文件 | #include <stdio.h> |
函数 | int fprintf(FILE *stream, const char *format, ...); int fscanf(FILE *stream, const char *format, ...); |
功能说明 | fprintf: 从文件指针stream指向的文件中,按format中对应的控制格式读取数据,并存储在agars对应的变量中; fwrite: 将agars(参数表)内各项的值,按format(格式控制字符串)所表示的格式,将数据格式为字符串的形式写入到文件指针stream指向的文件中 |
参数说明 |
|
下面针对上面的介绍的函数,结合起来写一个小程序(不可能每一个都是用到,但是大同小异):
/*********************
//功能:将文件的内容写入另一个新创建的文件
//
//
**********************/
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#define BUFSIZE 1024 //定义缓冲区大小
int main(int argc,char **argv)
{
/*fp1,指向已经存在的文件,fp2,指向我们新创建文件*/
FILE * fp1=NULL;
FILE * fp2=NULL;
char buf[BUFSIZE]={0};
if(argc<3)
{
printf("参数个较少\n");
exit(1);
}
if((fp1 = fopen(argv[1],"r")) == NULL){ //打开已存在文件,并赋予只读权限
perror("fopen()1");
exit(1);
}
if((fp2 = fopen(argv[2],"w")) == NULL){ //打开已存在文件,并赋予只写权限
perror("fopen()2");
exit(1);
}
while(1)
{
if(fread(buf,sizeof(char),BUFSIZE,fp1) == 0) break; //当读到文件的结尾的时候 跳出循环
fwrite(buf,sizeof(char),BUFSIZE,fp2);
}
fclose(fp1);
fclose(fp2);
exit(0);
}
下面是插图是 执行后,将C和指针 的内容复制写到自己定义的C文件中;大家可以随便任意类型的文件去试验下;