LinuxC语言文件i/o笔记(第十七天)
最近忙着比赛和学单片机了,原本想着不写博客了,但是发现不自己写一下相关的笔记,有点记不住这些东西,就还是抽时间写了。
标准i/o:
流的打开和关闭:
c语言和c++语言一致,也有关于文件的操作函数,也同要包含标准输入流什么的。
打开流:
在c语言中,我们通过 fopen 关键字打开标准i/o流:
FILE *fopen(const char *path,const char *mode);
第一个参数是文件名/地址,第二个参数为打开方式,分为六种:"r"、"r+"、"w"、"w+"、"a"、"a+",如果要打开二进制文件就在模式后面加个b,如"rb"。其中,w为只读,w+为读写,它们都要求文件存在,不然会错误;w为只写,w+为读写,它们如果没有文件会创建文件,若存在文件,则清空该文件 ;a和a+和w一致,但是是从文件末端写入数据,而且不清空原文件。
函数成功的话会返回流指针,否侧返回NULL。
#include <stdio.h>......FILE *fpsif((fps = fopen(argv[1],"r")) == NULL){perror("fopen src file");return -1;}......
fopen()函数创建的文件默认权限为0666(rw-rw-rw-)
处理错误信息:
extern int errno
errno为全局变量,存放错误的编号,错误1为无权限,11为无资源等;
void perror(const char *s);
可以打印错误信息,会先输出参数s,在输出errno的错误信息。
char *strerror(int errno);
可以根据错误号返回对应的错误信息,需要头文件<errno.h>,使用起来比上面的麻烦很多。
关闭流:
通过 fclose 关键字关闭标准i/o流:
int fclose(FILE *stream);
成功关闭会返回0,失败返回EOF,并自动设置errno。
关闭时会自动把缓冲区数据写入并释放缓冲区。
虽然程序结束后会自动关闭流,但为了规范和防止出问题,还是要记得写fclose。
按字符输入输出:
c语言有三种输入输出方式,第一个就是按字符输入输出:
int fgetc(FILE *stream);
int getc(FILE *stream);
int getchar(void);
成功时会返回读取到的字符,到文件末尾或出错就会返回EOF。
getchar()是从标准输入流(即终端)获取一个字符。前两个函数当FILE *stream = stdin时,等同于getchar(),stdin就是终端标准流。
输出也有三个函数:
int fputc(int c,FILE *stream);
int putc(int c,FILE *stream);
int putchar(void);
成功的话返回写入的字符,出错返回EOF
putchar()等同于fputc(c,stdout),stdout为标准输出流(即终端)。
#include <stdio.h>int main(int argc,char *argv[]){FILE *fps,*fpd;int ch;if(argc < 3){printf("Usage : %s <sre_file> <dst_file>\n",argv[0]);return -1;}if((fps = fopen(argv[1],"r")) == NULL){perror("fopen src file");return -1;}if((fpd = fopen(argv[2],"w")) == NULL){perror("fopen src file");return -1;}while((ch = fgetc(fps)) != EOF){fputc(ch,fpd);}fclose(fps);fclose(fpd);return 0;
}
使用程序的时候要附带输入输出的文件:
./test text textcp前者必须存在,因为用的是r只读模式,后者可以不存在,w模式若不存在文件会自动创建一个。
按行输入输出:
不好用!不好用!不好用!
使用不当会导致缓冲区溢出等。
输入函数为:
char *gets(char *a);
char *fget(char *a,int size,FILE *stream);
gets主要用于在标准输入读取一行,和c++的getline很像,但只指定了缓冲区的头地址,而无长度,就容易缓冲区溢出。
fget是从指定流中读取一行写入缓冲区,是指定大小,指定流的读取。
成功的话返回写入的缓冲区a,到末尾或出错时返回NULL。
遇到"\n"或已读取了size-1个字符时返回,末尾会自动加'\0'表示其为字符串。
其中a为char *a[],即字符串,c语言中是没有string的,所以只能使用字符数组。
输出函数和输入函数类似:
int puts(const char *a);
int fputs(const char *a,FILE *stream);
成功的话返回写入的流的字符个数,到末尾或出错时返回EOF。
puts将a输入到stdout时会追加'\n',fputs不会追加换行符。
按对象输入输出:
size_t fread(void *prt,size_t size,size_t n,FILE *fp);
size_t fwrite(const void *prt,size_t size,size_t n,FILE *fp);
数据文件为整数,就可以以整型对象去读取,若为字符,就以以字符对象读取。
prt为缓冲区,要自己先定义好,size为每个对象的大小,字符为1字节,整型为4字节,n为读取输出的对象长度,fp为输入输出流。
成功返回实际读写的对象个数,出错返回EOF。
#include <stdio.h>
#define N 64
int main(int argc ,char *argv[]){FILE *fps,*fpd;char buf[N];int n;if(argc < 3){printf("Usage : %s <sre_file> <dst_file>\n",argv[0]);return -1;}if((fps = fopen(argv[1],"r")) == NULL){perror("fopen src file");return -1;}if((fpd = fopen(argv[2],"w")) == NULL){perror("fopen src file");return -1;}while((n = fread(buf,1,N,fps)) > 0){fwrite(buf,1,n,fpd);}fclose(fps);fclose(fpd);return 0;
}
fgetc/fputc 效率低但安全
fgets/fputs 效率较高,但是不安全,而且只能文本读写
fread/fwrite 效率高,安全,可以指定读取,节省内存等
流的相关操作:
刷新流:
int fflush(DILE *fp);
正常程序中,只用关闭流或程序结束的时候,缓冲区的数据才会实际写入文件,但如果遇到要长期运行的程序就会导致数据转移失败或延后,就可以对当前的输入输出流进行刷新,将缓冲区的数据马上写入实际的文件,但Linux系统只能对输出流进行刷新。
成功的时候返回0,失败返回EOF;
定位流:
long ftell(FILE *fp);
long fseek(ILE *fp,long offset,int whence);
long rewind(ILE *fp);
ftell返回的是当前读写的位置,出错返回EOF;
fseek参数为流指针、偏移量和指定位置,指定位置参数为(SEEK_SET(开始位置),SEEK_CUP(当前位置),SEEK_END(文件末尾)),成功返回流,失败为EOF。
rewind就是把文件定位回开头,即fseek(fp,0,SEEK_SET)。
判断流的出错和结束:
上面错误流讲过error函数了,就不再多讲。
判断流是否结束的函数为
int feof(FILE *fp);
返回1表示已到末尾,返回0则未到。
#include <stdio.h>
int main(){FILE *fp;if((fp = fopen("test.txt","r+")) == NULL){perror("fopen");return -1;}fseek(fp,0,SEEK_END);fputc('t',fp);fflush(fp);printf("ftell(fp) = %ld\n", ftell(fp));if(feof(fp) == 1){printf("到达文件末端\n");}fclose(fp);return 0;
}
格式化输出:
在c语言中,我们经常用到printf进行输出,在流里,还有两种:
int fprintf(FILE *FP,const char *fmt,....);
int sprintf(char *a,const char *fmt,...);
和printf一样,fmt为“%d”,time这样把像输入的东西按照%d,%s什么的格式输入进流,fprintf是输入到文件,sprintf为输入到缓冲区里。
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
int main(){FILE *fp;int line = 0;char buf[64];time_t t;struct tm *tp;if((fp = fopen("test.txt","a+")) == NULL){perror("fopen");return -1;}while(fgets(buf,64,fp) != NULL){if(buf[strlen(buf) - 1] == '\n') { line++; }}while(1){time(&t);tp = localtime(&t);fprintf(fp,"%02d,%d-%02d-%02d %02d:%02d:%02d\n",++line,tp->tm_year+1900,tp->tm_mon+1,tp->tm_mday,tp->tm_hour,tp->tm_min,tp->tm_sec);fflush(fp);sleep(1);}return 0;
}