1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 【Linux】系统编程之文件(标准I/O库)

【Linux】系统编程之文件(标准I/O库)

时间:2020-04-28 17:58:29

相关推荐

【Linux】系统编程之文件(标准I/O库)

目录

一、文件I/O与标准I/O的区别(open与fopen)1、来源2、移植性3、适用范围4、文件IO层次5、缓冲二、函数fopen、fwrite、fread、fseek、fclose1、函数fopen2、函数fwrite3、函数fread4、函数fseek5、函数fclose三、用标准I/O库的函数将整数、结构体和结构体数组写进文件1、将整数写进文件2、将结构体写进文件3、将结构体数组写进文件四、函数fputc、fputs、feof、fgetc、fgets1、fputc和fputs2、feof3、fgetc和fgets

一、文件I/O与标准I/O的区别(open与fopen)

1、来源

从来源的角度看,两者能很好的区分开,这也是两者最显而易见的区别:

open是UNIX系统调用函数(包括LINUX等),返回的是文件描述符(File Descriptor),它是文件在文件描述符表里的索引。fopen是ANSIC标准中的C语言库函数,在不同的系统中应该调用不同的内核api。返回的是一个指向文件结构的指针。

PS:从来源来看,两者是有千丝万缕的联系的,毕竟C语言的库函数还是需要调用系统API实现的。

2、移植性

这一点从上面的来源就可以推断出来,fopen是C标准函数,因此拥有良好的移植性;而open是UNIX系统调用,移植性有限。如windows下相似的功能使用API函数CreateFile

3、适用范围

open返回文件描述符,而文件描述符是UNIX系统下的一个重要概念,UNIX下的一切设备都是以文件的形式操作。如网络套接字、硬件设备等。当然包括操作普通正规文(Regular File)。fopen是用来操纵普通正规文件(Regular File)的。

4、文件IO层次

如果从文件IO的角度来看,前者属于低级IO函数,后者属于高级IO函数。低级和高级的简单区分标准是:谁离系统内核更近。低级文件IO运行在内核态,高级文件IO运行在用户态。

5、缓冲

1、缓冲文件系统

缓冲文件系统的特点是:在内存开辟一个“缓冲区”,为程序中的每一个文件使用;当执行读文件的操作时,从磁盘文件将数据先读入内存“缓冲区”,装满后再从内存“缓冲区”依此读出需要的数据。执行写文件的操作时,先将数据写入内存“缓冲区”,待内存“缓冲区”装满后再写入文件。由此可以看出,内存“缓冲区”的大小,影响着实际操作外存的次数,内存“缓冲区”越大,则操作外存的次数就少,执行速度就快、效率高。一般来说,文件“缓冲区”的大小随机器 而定。fopen, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, freopen, fseek, ftell, rewind等。

2、非缓冲文件系统

缓冲文件系统是借助文件结构体指针来对文件进行管理,通过文件指针来对文件进行访问,既可以读写字符、字符串、格式化数据,也可以读写二进制数据。非缓冲文件系统依赖于操作系统,通过操作系统的功能对文件进行读写,是系统级的输入输出,它不设文件结构体指针,只能读写二进制文件,但效率高、速度快,由于ANSI标准不再包括非缓冲文件系统,因此建议大家最好不要选择它。open, close, read, write, getc, getchar, putc, putchar等。

两种I/O模型的比较

一句话总结一下,就是open无缓冲,fopen有缓冲。前者与read,write等配合使用, 后者与fread,fwrite等配合使用。

使用fopen函数,由于在用户态下就有了缓冲,因此进行文件读写操作的时候就减少了用户态和内核态的切换(切换到内核态调用还是需要调用系统调用API:readwrite);而使用open函数,在文件读写时则每次都需要进行内核态和用户态的切换;表现为,如果顺序访问文件,fopen系列的函数要比直接调用open系列的函数快;如果随机访问文件则相反。

二、函数fopen、fwrite、fread、fseek、fclose

前提知识

<文件指针>

文件指针实际上是指向一个结构体类型的指针,这个结构体中包含有诸如:缓冲区的地址、在缓冲区中当前存取的字符的位置、对文件是“读”还是“写”、是否出错、是否已经遇到文件结束标志等信息。用户不必去了解其中的细节,所有一切都在 stdio.h 头文件中进行了定义。一般称上面提到的结构体类型名为 FILE,定义文件类型指针变量的一般形式为:

FILE *指针变量名;

例如:FILE *fp1, *fp2;

fp1fp2均被定义为指向文件类型的指针变量,称为文件指针

1、函数fopen

函数原型:

#include <stdio.h>FILE *fopen(const char *pathname, const char *mode);

参数介绍:

pathname:包含要打开的文件路径及文件名(含路径,缺省为当前路径);

mode:文件打开状态;

mode 打开模式:

返回值:

若成功,返回指向FILE的指针(文件指针)

若出错,返回NULL

2、函数fwrite

函数原型:

#include <stdio.h>size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);

参数介绍:char *str = "Apibro is very nice!";

ptr:存放写入记录的缓冲区(相当于buf缓冲区)

size:写入的记录大小(要写多少字节数),即sizeof(char)

nmemb:写入的记录数(要写多少个数据项,每个数据项长度为size),即strlen(str)

stream:要写入的文件流(哪个文件)

返回值:

若成功,返回实际写入的nmemb数目(size_t nmemb为一个整型数,即写入的次数)

若出错,EOF(End of File)

3、函数fread

函数原型:

#include <stdio.h>size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

参数介绍:char *str = "Apibro is very nice!";

ptr:存放读入记录的缓冲区(相当于buf缓冲区)

size:读取的记录大小(要读多少字节数),即sizeof(char)

nmemb:读取的记录数(要读多少个数据项,每个数据项长度为size),即strlen(str)

stream:要读取的文件流(哪个文件)

返回值:

若成功,返回实际读取的nmemb数目(size_t nmemb为一个整型数,即读取的次数)

若出错,EOF(End of File),即-1

4、函数fseek

函数原型:

#include <stdio.h>int fseek(FILE *stream, long offset, int whence);

参数介绍:

stream:要操作的文件流(哪个文件)

offset:偏移量

whence:当前位置的基点

与lseek类似,见【Linux】系统编程之文件(常用API)----函数lseek

返回值:

若成功 , 返回0

若失败,返回非0, 并设置error错误代码

5、函数fclose

函数原型:

#include <stdio.h>int fclose(FILE *stream);

参数介绍:

stream:已打开的文件指针

返回值:

若成功 , 返回0

若出错,EOF(End of File),即-1

综合示例

代码:

#include <stdio.h>#include <string.h>#include <stdlib.h>int main(){FILE *fp;char *str = "Apibro is very nice!";char *readBuf = NULL;//FILE *fopen(const char *pathname, const char *mode);fp = fopen("./lu.txt","w+");//int n_fwrite = fwrite(str,sizeof(char),strlen(str),fp);第一种//int n_fwrite = fwrite(str,sizeof(char)*strlen(str),1,fp);第二种,这两种写法一个意思int n_fwrite = fwrite(str,sizeof(char)*strlen(str),10,fp);//fwrite返回值与第三个参数有关,第三个参数是多少就多少//int fseek(FILE *stream, long offset, int whence);fseek(fp,0,SEEK_SET);readBuf = (char *)malloc(sizeof(char)*n_fwrite + 10240);//fread(readBuf,sizeof(char),strlen(str),fp);第一种//int n_fread = fread(readBuf,sizeof(char)*strlen(str),1,fp);第二种,这两种写法一个意思int n_fread = fread(readBuf,sizeof(char)*strlen(str),5,fp);//fread返回值也与第三个参数有关,当第三个参数大于等于n_fwrite时,返回值为n_fwrite;当第三个参数小于n_fwrite时,返回值为第三个参数值printf("read data: %s\n",readBuf);printf("write = %d,read = %d\n",n_fwrite,n_fread);fclose(fp);return 0;}

结果:

注意点:

fwrite返回值与第三个参数有关,第三个参数是多少就多少fread返回值也与第三个参数有关,当第三个参数大于等于n_fwrite时,返回值为n_fwrite;当第三个参数小于n_fwrite时,返回值为第三个参数值

三、用标准I/O库的函数将整数、结构体和结构体数组写进文件

1、将整数写进文件

代码:

#include <stdio.h>int main(){FILE *fp;//指向文件的一个指针fpint date1 = 66;int date2;fp = fopen("./file1","w+");int n_fwrite = fwrite(&date1,sizeof(int),1,fp);fseek(fp,0,SEEK_SET);int n_fread = fread(&date2,sizeof(int),1,fp);printf("read %d\n",date2);fclose(fp);return 0;}

结果:

2、将结构体写进文件

代码:

#include <stdio.h>struct Test{int a;char c;};int main(){FILE *fp;//指向文件的一个指针fpstruct Test date1 = {100,'c'};struct Test date2;fp = fopen("./file1","w+");int n_fwrite = fwrite(&date1,sizeof(struct Test),1,fp);fseek(fp,0,SEEK_SET);//光标定位int n_fread = fread(&date2,sizeof(struct Test),1,fp);printf("read %d,%c\n",date2.a,date2.c);fclose(fp);return 0;}

结果:

3、将结构体数组写进文件

代码:

#include <stdio.h>struct Test{int a;char c;};int main(){FILE *fp;//指向文件的一个指针fpstruct Test date1[2] = {{100,'c'},{200,'d'}};struct Test date2[2];fp = fopen("./file1","w+");int n_fwrite = fwrite(&date1,sizeof(struct Test)*2,1,fp);fseek(fp,0,SEEK_SET);//光标定位int n_fread = fread(&date2,sizeof(struct Test)*2,1,fp);printf("read %d,%c\n",date2[0].a,date2[0].c);printf("read %d,%c\n",date2[1].a,date2[1].c);fclose(fp);return 0;}

结果:

四、函数fputc、fputs、feof、fgetc、fgets

1、fputc和fputs

作用:

fputc(ch,fp)把字符ch写到文件指针变量fp所指向的文件中

fputs(str,fp)把str所指向的字符串写到文件指针变量fp所指向的文件中

函数原型:

#include <stdio.h>int fputc(int c, FILE *stream);int fputs(const char *s, FILE *stream);

参数介绍:

c:要输出的字符

s:要输出的字符串

stream:对应的(输出的)文件流fp

返回值:

若成功,fputc返回字符c、fputs返回s(字符串首地址)非负值

若已达到文件尾端或出错,fputc返回EOF,即-1、fputs返回NULL

示例1

代码:

#include <stdio.h>#include <string.h>int main(){FILE *fp;char *str = "Apibro is very nice!";int i;int len = strlen(str);fp = fopen("./test.txt","w+");for(i=0;i<len;i++){fputc(*str,fp);str++;}fputs("qwertyui",fp);fclose(fp);return 0;}

结果:(未用fseek重新定位光标,所以内容接在后面写了)

2、feof

作用:检查到文件读写位置标记是否移到文件的末尾,即,磁盘文件是否结束。

函数原型:

#include <stdio.h>int feof(FILE *stream);

参数介绍:

stream:对应的文件流fp

返回值:

若fp指向的文件结束,函数值为1(真)

若fp指向的文件没有结束,含函数值为0(假)

示例2

用到fgetc,下面有介绍,请往下翻阅。

代码:

#include <stdio.h>#include <string.h>#include <stdlib.h>int main(){FILE *fp;char c;char msg[50] = "Apibro is very nice!";fp = fopen("./test.txt","r+");while(!feof(fp)){//int fgetc(FILE *stream);c = fgetc(fp);//若读到文件尾或出现错误时,它就返回EOFprintf("%c",c); }printf("\n");fclose(fp);return 0;}

结果:

这里读到文件尾或出现错误时,它就返回EOF,也打印出来就多了个问号?

注意:这里!feof(fp),即当fp没有移到文件尾就返回0,!0就是1,while继续执行;当fp移到文件尾就返回1,!1就是0,跳出while循环

3、fgetc和fgets

作用:

fgetc(fp)从fp指向的文件读入一个字符

fgets(str,n,fp)从fp指向的文件读入一个长度为(n-1)的字符串,存放到字符数组str中

函数原型:

#include <stdio.h>int fgetc(FILE *stream);char *fgets(char *s, int size, FILE *stream);

参数介绍:

s:要输入的字符串

size:输入字符串长度

stream:对应的(输入的)文件流fp

返回值:

若成功,fgetc返回下一个字符(带回所读的字符)、fgets返回s(字符串首地址)

若已达到文件尾端或出错,fgetc返回EOF,即-1、fgets返回NULL

示例3

代码:

#include <stdio.h>#include <string.h>#include <stdlib.h>int main(){FILE *fp;char c;char msg[50] = "Apibro is very nice!";char msg2[50];fp = fopen("./test2.txt","r+");//int fputs(const char *s, FILE *stream);fputs(msg,fp);//把msg写到文件fp里//int fseek(FILE *stream, long offset, int whence);fseek(fp,0,SEEK_SET);//光标移至文件头//char *fgets(char *s, int size, FILE *stream);fgets(msg2,50,fp);//读取fp指向的文件中50个字节放到msg2中printf("str=%s\n",msg2);fclose(fp);return 0;}

结果:

最后谢谢阅读,笔者乃小白,如有错误之处还请指正。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。