怎么免费建立网站做推广,wordpress类似于mdx主题,临沂网站建设培训,防城港网站建设系统IO的最大特点一个是更具通用性#xff0c;不管是普通文件、管道文件、设备节点文件、接字文件等等都可以使用#xff0c;另一个是他的简约性#xff0c;对文件内数据的读写在任何情况下都是带任何格式的#xff0c;而且数据的读写也都没有经过任何缓冲处理#xff0c;… 系统IO的最大特点一个是更具通用性不管是普通文件、管道文件、设备节点文件、接字文件等等都可以使用另一个是他的简约性对文件内数据的读写在任何情况下都是带任何格式的而且数据的读写也都没有经过任何缓冲处理这样做的理由是尽量精简内API而更加丰富的功能应该交给第三方库去进一步完善。 标准C库是最常用的第三方库而标准IO就是标准C库中的一部分接口这一部分口实际上是系统IO的封装他提供了更加丰富的读写方式比如可以按格式读写、按SCII码字符读写、按二进制读写、按行读写、按数据块读写等等还可以提供数据读写冲功能极大提高程序读写效率。 所有的系统IO函数都是围绕所谓的“文件描述符”进行的这个文件描符由函数open获取而所有的标准IO都是围绕所谓的“文件指针”进的这个文件指针则是由fopen获取的他是第一个需要掌握的标准IO函数 打开/关闭 返回值的文件指针是一种指向FILE{}的结构体在标准IO中被定义 可以看到使用标准IO函数处理文件的最大特点是数据将会先存储在一个标准IO缓冲区中而后在一定条件下才被一并flush冲洗或称刷新至内核缓冲区而不是像系统IO那样数据直接被 flush至内核。
注意到标准IO函数 fopen实质上是系统IO函数 open的封装他们是一一对应的每一次fopen都会导致系统分配一个file{}结构体和一个FILE{}来保存维护该文件的读写信息每一次的打开和操作都可以不一样是相对独立的因此可以在多线程或者多进程中多次打开同一个文件再利用文件空洞技术进行多点读写。
另外由上一节得知标准输入输出设备是默认被打开的在标准IO中也是一样他们在程序的一开始就已经拥有相应的文件指针了 跟fopen配合使用的是fclose函数 读写
标准IO的读写函数接非常多下面列出最常用的函数集合
第一组读写一个字符的函数 需要注意的几点
1,fgec()、getc()和getchar()返回值是int,而不是char,原因是因为他们在出 错或者读到文件末尾的时候需要返回一个值为—1的EOF标记而char型数据有可能因为系统的差异而无法表示负整数。
2当fgec、getc和getchar返回EOF时有可能是发生了错误也有可能是读到了文件末尾这是要用以下两个函数接口来进一步加以判断 3getchar缺省从标准输入设备读取一个字符。
4putchar缺省从标准输出设备输出一个字符。
5,fgetc()和fputc()是函数getc()和putc()是宏定义。
6,两组输入输出函数一般成对地使用fgetc()和fputc(),getc()和putc(), getchar()和 putchar().
一个例子将这些函数的使用方法综合
#include stdio.h
#include sys/stat.h
#include sys/types.h
#include fcntl.h
#include unistd.h
#include string.h
#include strings.h
#include stdlib.h
#include stdbool.h
#include errno.hint main(int argc, char const *argv[])
{FILE *fp1 fopen(in.txt,w);FILE *fp2 fopen(out.txt,r);if(fp1 NULL || fp2 NULL){perror(fopen());exit(1);}int c,total 0;while (1){c fgetc(fp2);if(c EOF feof(fp2)){printf(copy compeleted,%d was been copied\n,total);break;}else if(ferror(fp2)){perror(fgetc());break;}fputc(c,fp1);total;}fclose(fp1);fclose(fp2);return 0;
}第二组每次一行的读写函数 值得注意的有以下几点
1fgets跟fgetc一样当其返回NULL时并不能确定究竟是达到文件末尾还是碰到错误需要用 feof/ferror来进一步判断。
2fgets每次读取至多不超过size个字节的一行所谓“一行”即数据至多包含一个换行符\n′。
3gets是一个已经过时的接口因为他没有指定自定义缓冲区s的大小这样很容易造成缓冲区溢出导致程序段访问错误。
4,fgets()和fputs(),gets()和puts()一般成对使用鉴于gets()的不安全性 一般建议使用前者。
下面是使用该组函数实现的普通文件拷贝示例代码
#include stdio.h
#include stdlib.h
#include stdbool.hstruct node //栈节点结构体
{int data;struct node *next;
};struct linked_stack //管理结构体
{int size;struct node *top; //指向栈顶节点
};struct linked_stack *init_stack (void)
{struct linked_stack *s;s malloc(sizeof(struct linked_stack));if(s ! NULL){s-size 0;s-top NULL;}return s;
}//创建新节点
struct node *new_node(int data)
{struct node *new;new malloc(sizeof(struct node));if(new ! NULL){new-data data;new-next NULL;}return new;
}//压栈
bool push(struct linked_stack *s,struct node *new)
{if (s NULL || new NULL)return false;new-next s-top;s-top new;s-size;return true;
}bool stack_empty(struct linked_stack *s)
{return s-size 0;
}bool pop(struct linked_stack *s,struct node **p)
{if(s NULL || p NULL || stack_empty(s))return false;*p s-top;s-top s-top-next;(*p)-next NULL;s-size--;return true;
}void show(struct linked_stack *A,struct linked_stack *B,struct linked_stack *C)
{FILE *fp; /*建立文件指针*/fp fopen(/mnt/e/GZ2112/程序入门/test_txt/hano.txt,a);int maxlen,len;maxlen A-size B-size ? A-size : B-size;maxlen maxlen C-size ? maxlen : C-size;len maxlen;struct node *t1 A-top;struct node *t2 B-top;struct node *t3 C-top;int i;for (i 0; i maxlen; i){if(t1 ! NULL len A-size){fprintf(fp,%d,t1-data);t1 t1-next;}fprintf(fp,\t);if(t2 ! NULL len B-size){fprintf(fp,%d,t2-data);t2 t2-next;}fprintf(fp,\t);if(t3 ! NULL len C-size){fprintf(fp,%d,t3-data);t3 t3-next;}fprintf(fp,\t);fprintf(fp,\n);len--;}fprintf(fp,A\tB\tC\n);fprintf(fp,-----------------\n);fclose(fp);
}void hano(struct linked_stack *A,struct linked_stack *B,struct linked_stack *C,int n)
{if(n 0)return;struct node *tmp;hano(A,C,B,n-1); //将n-1块从A借助C移向Bgetchar(); //每回车一次进行一步show(A,B,C);pop(A,tmp);push(C,tmp); //将A最下面一块移动到Chano(B,A,C,n-1); //将n-1块从B借助A移向C
}int main(int argc, char const *argv[])
{struct linked_stack *A init_stack();struct linked_stack *B init_stack();struct linked_stack *C init_stack();int hanois 0;scanf(%d,hanois);int i;for (i 0; i hanois; i){struct node *new new_node(hanois-i); //将汉诺塔中的块放入栈A柱Apush(A,new);}hano(A,B,C,hanois);show(A,B,C);return 0;
}第三组每次读写若干数据块的标准IO接口函数 这一组标准IO函数被称为“直接IO函数”或者“二进制IO函数”因为他们对数据的读写严格按照规定的数据块数和数据块的大小来处理而不会对数据格式做任何处理而且当数据块中出现特殊字符比如换行符”\n、字符串结束标记”\0等时不会受到影响。需要注意的几点
1如果fread返回值小于nmemb时则可能已达末尾或者遇到错误需要借助于feof()/ferror()来加以进一步判断。
2当发生上述第1种情况时其返回值并不能真正反映其读取或者写入的数据块数而只是一个所谓的“截短值”比如正常读取5个数据块每个数据块100个字节在执行成功的情况下返回值是5表示读到5个数据块总共500个字节但是如果只读到499个数据块那么返回值就变成4而如果读到99个字节那么fread会返回0。因此当发生返回值小于nmemb时需要仔细确定究竟读取了几个字节而不能直接从返回值确定。
第四组获取或设置文件当前位置偏移量 注意 1.fseek函数的使用基本与lseek函数相同 2.rewindfp相当于fseekfp0LSEEK_SET)
利用上面两组函数再次实现读写功能
#include stdio.h
#include sys/stat.h
#include sys/types.h
#include fcntl.h
#include unistd.h
#include string.h
#include strings.h
#include stdlib.h
#include stdbool.h
#include errno.h#define BUFSIZE 100
#define NMEMB 5int main(int argc, char const *argv[])
{FILE *fp1 fopen(in.txt,w);FILE *fp2 fopen(out.txt,r);if(fp1 NULL || fp2 NULL){perror(fopen());exit(1);}char buf[BUFSIZE];int total 0;long pos1 , pos2;while (1){bzero(buf,BUFSIZE);pos1 ftell(fp2);if (fread(buf,BUFSIZE,NMEMB,fp2) NMEMB){if(feof(fp2)){//将未满NMENB的数据写入pos2 ftell(fp2);fwrite(buf,pos2 - pos1,1,fp1);total pos2-pos1; printf(copy compeleted,%d was been copied\n,total);break;}else if(ferror(fp2)){perror(fgetc());break;}}fwrite(buf,BUFSIZE,NMEMB,fp1);total BUFSIZE * NMEMB;}fclose(fp1);fclose(fp2);return 0;
}第五组标准格式化IO函数 格式化IO函数中最常用的莫过于printf()和scanf()了但从上表中可以看到他们其实各自都有一些功能类似的兄弟函数可用使用这些函数需要注意以下几点 1,fprintf()不仅可以像printf()一样向标准输出设备输出信息也可以向由stream指定的任何有相应权限的文件写入数据。 2,sprintf()和snprintf()都是向一块自定义缓冲区写入数据不同的是后者第二个参数提供了这块缓冲区的大小避免缓冲区溢出因此应尽量使用后者放弃使用前者。 3,fscanf()不仅可以像scanf()一样从标准输入设备读入信息也可以从由stream指定的任何有相应权限的文件读入数据。 4,sscanf()从一块由s指定的自定义缓冲区中读入数据。 5,最重要的一条这些函数的读写都是带格式的这些所谓的格式由下表规定 这一组函数与之前最大的区别在于带有格式控制因此适用于有格式的文件处理比如学生信息等等此类数据。