一、打开、读写、关闭
1.1 fopen
一般用a+
#include <stdio.h> #include <stdlib.h> int main(int argc, char const *argv[]) { FILE *fp; //fp = fopen("a.txt","w+"); fp = fopen(argv[1],"a+"); if (NULL == fp) { printf("file a.txt error!\n"); exit(1); } return 0; }
加b可以以二进制打开文件,不加为字符打开
1.2 fclose
FILE *fp; fp = fopen(argv[1],"a+"); fclose(fp);
1.3 fwrite
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
const void *ptr:要写入的数据指针
size_t size:每次写size字节
size_t nmemb:总共写nmemb次
FILE *stream:所写入的文件
返回值:nmemb(写了多少次)
出错是0
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char const *argv[]) { FILE *fp; //fp = fopen("a.txt","w+"); fp = fopen(argv[1],"a+"); //fp = fopen(argv[1],"r"); if (NULL == fp) { printf("file a.txt error!\n"); exit(1); } char buffer[1024] = "hello world"; int ret = fwrite(buffer,1,strlen(buffer),fp); printf("ret = %d\n",ret); return 0; }
1.4 fread
size_t fread(void *ptr, size_t size, size_t nmemb,FILE *stream);
void *ptr:要写入的数据指针
size_t size:每次读size字节
size_t nmemb:总共读nmemb次
FILE *stream:所写入的文件
返回值:nmemb(读了多少次)
出错是0
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char const *argv[]) { FILE *fp; //fp = fopen("a.txt","w+"); fp = fopen(argv[1],"a+"); if (NULL == fp) { printf("file a.txt error!\n"); exit(1); } char buffer[1024] = "hello world"; int ret = fwrite(buffer,1,strlen(buffer),fp); printf("ret = %d\n",ret); memset(buffer,0,sizeof(buffer)); ret = fread(buffer,1,ret,fp); buffer[ret] = '\0'; printf("read buffer = %s\n",buffer); return 0; } //读不出来,是因为文件读写位置指针指向末尾
文件读写指针
二、fseek、feof、ftell
int fseek(FILE *stream, long offset, int whence);
FILE *stream 目标文件
long offset 偏移量(正数是后移,负数是前移)
int whence 锁定位置(配图)
顺序:先锁定位置,再判断偏移量
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char const *argv[]) { FILE *fp; //fp = fopen("a.txt","w+"); fp = fopen(argv[1],"a+"); if (NULL == fp) { printf("file a.txt error!\n"); exit(1); } char buffer[1024] = "hello world"; int ret = fwrite(buffer,1,strlen(buffer),fp); if(0 == ret) { printf("fwrite a.txt error!\n"); exit(1); } printf("ret = %d\n",ret); ret = fseek(fp,0,SEEK_SET); if(-1 == ret) { printf("fseek a.txt error!\n"); exit(1); } memset(buffer,0,sizeof(buffer)); ret = fread(buffer,1,ret,fp); if(0 == ret) { printf("fread a.txt error!\n"); exit(1); } buffer[ret] = '\0'; printf("read buffer = %s\n",buffer); return 0; }
2.1 实现写读写一行
2.1.1 写
fwrite("\n",1,1,fp);
2.1.2 读(feof、ftell、rewind)
文档结尾有个隐藏字符EOF
int feof(FILE *stream);
文件结束:返回非0值;文件未结束:返回0值
ftell:用来得到文件指针离文件开头的偏移量
long ftell(FILE *stream);
rewind()用于文件指针移动到文件的开头,当移动成功时
void rewind(FILE *stream);
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char const *argv[]) { FILE *fp; //fp = fopen("a.txt","w+"); fp = fopen(argv[1], "a+"); if (NULL == fp) { printf("file a.txt error!\n"); exit(1); } char buffer[1024] = "hello world"; int ret = fwrite(buffer, 1, strlen(buffer), fp); fwrite("\n", 1, 1, fp); if (0 == ret) { printf("fwrite a.txt error!\n"); exit(1); } printf("ret = %d\n", ret); ret = fseek(fp, 0, SEEK_SET); if (-1 == ret) { printf("fseek a.txt error!\n"); exit(1); } memset(buffer,0,sizeof(buffer)); char temp; int i = 0; while (!feof(fp)) { if(fread(&temp, 1, 1, fp) == -1) { printf("file fread error!\n"); } buffer[i] = temp; i++; } #if 0 ret = fread(buffer,1,ret,fp); if(0 == ret) { printf("fread a.txt error!\n"); exit(1); } #endif buffer[i] = '\0'; printf("read buffer = %s\n",buffer); fclose(fp); return 0; }
2.2 feof经典错误案例
2.2.1 原理
原理:站在光标所在位置,向后面看看有没有字符,如果有,返回0;如果没有,返回非0。它并不会读取相关信息,只会查看光标后是否有内容
功能:检测文件结束符EOF
2.2.2 判断一个文件是否为空
#include <stdio.h> int main(int argc, char *argv[]) { FILE *fp; fp = fopen(argv[1], "a+"); #if 0 if (feof(fp) == 0) { printf("file is empty\n"); } #endif if (feof(fp) != 0) { printf("file is empty\n"); } fclose(fp); return 0; }
现象:feof并不能判断空文件,返回为0
原因:当文件内部的位置指针指向文件结束时,并不会立即设置FILE结构中的文件结束标识,只有再执行一次读文件操作,才会设置结束标志,此后调用feof()才会返回为真。
解决
#include <stdio.h> int main(int argc, char const *argv[]) { FILE *p; getc(p); if (feof(p)) { printf("file is empty.\n"); } else { rewind(p);//将光标跳回到文件开头 int a; fscanf(p,"%d",&a); printf("%d",a); } return 0; }
//例如,有一个文件指针fp,文件中有字符串“hello world”: int c=0; while( !feof(fp) ) { int c=fgetc(fp); printf("%c: %x \n", c, c); } //上面的代码除了输出 hello 外,还会输出一个结束字符EOF(EOF是fgetc函数的返回值, //并不是文件中存在EOF)。其原因就是当内部位置指针指向结尾时, //还要执行一次读操作,文件结束标识才会被设置。 //修改 int c; c=fgetc(fp); while( !feof(fp) ) { printf("%c: %x \n", c, c); c=fgetc(fp); } //上面的代码只输出“hello”不输出文件结束符EOF。 //当文件内部位置指针指向结束位置时,先执行一次读操作, //设置文件结束标识,while循环立即结束。
参考网站:C语言feof()函数:检查流上文件的结束标识(是否读到文件结尾)
2.3 实现将一个文件拷贝给另一个文件
#include <stdio.h> #include <stdlib.h> #include <string.h> void isOK(FILE *fp, char *filename) { if (fp == NULL) { printf("%s open error!\n", filename); exit(1); } } int main(int argc, char *argv[]) { if (argc != 3) { printf("Please input file name!\n"); exit(1); } FILE *to_fp; FILE *from_fp; char buffer[1024] = {0}; from_fp = fopen(argv[1], "r"); isOK(from_fp, argv[1]); to_fp = fopen(argv[2], "a+"); isOK(to_fp, argv[2]); fseek(to_fp, 0, SEEK_SET); //rewind(to_fp); fseek(from_fp, 0, SEEK_END); int w_len; int file_size = ftell(from_fp); fseek(from_fp, 0, SEEK_SET); while (!feof(from_fp)) { memset(buffer, 0, sizeof(buffer)); fread(buffer, 1, sizeof(buffer) - 1, from_fp); w_len = fwrite(buffer, 1, strlen(buffer), to_fp); //printf("%s\n", buffer); file_size = file_size - w_len; if (file_size < 0) { break; } } return 0; }
三、fgetc、fgets、getc、getchar
getchar:从终端上获取一个字符
fgetc:
头文件:#include 原型:int fgetc(FILE *stream) 功能:从文件中获取一个字符 参数:stream 目标文件指针 返回值:该字符所对应的ASCII码,若返回`EOF`则表示到了文件尾
getc:
getc()和fgetc(),作用相同,但是getc()是宏定义,非真正的函数调用
char temp; while ((temp = fgetc(from_fp)) != EOF) { fputc(temp, to_fp) } return 0; }
fgets
头文件:#include 原型:char *fgets(char *s, int size, FILE *stream) 功能: 读取stream一行,存储到s中。当读取 (size-1) 个字符时, 或者读取到换行符时,或者到达文件末尾时,它会停止,并加上`\0` 参数: s 这是指向一个字符数组的指针,该数组存储了要读取的字符串 size 这是要读取的最大字符数(包括最后的空字符)。通常是使用以 str 传递的数组长度。 stream 这是指向 FILE 对象的指针,该 FILE 对象标识了要从中读取字符的流。 返回值: 如果成功,该函数返回相同的 s 指针。失败则返回`NULL`。 如果发生错误,返回一个空指针。
fgets(buffer, sizeof(buffer), from_fp); buffer[strlen(buffer) - 1] = '\0'; //把读取到的`\n`给去除 printf("%s\n", buffer); //打印:#include <stdio.h>
四、fputc、fputs、putc、putchar
putchar:从终端上输出一个字符
fputc:
头文件:#include 原型:int fputc(int c, FILE *stream) 功能:向stream写入一个字符c 参数: c 你要输入的字符(int 是其ASCII) stream 你要输入的文件指针 返回值:如果没有发生错误,则返回被写入的字符。如果发生错误,则返回 EOF
char temp; while ((temp = fgetc(from_fp)) != EOF) { fputc(temp, to_fp) } return 0; }
putc:
putc()和fputc(),作用相同,但是putc()是宏定义,非真正的函数调用
fputs
头文件:#include 原型:int *fputs(const char *s, FILE *stream) 功能:把字符串写入到指定的流 stream 中,但不包括``\0。 参数: s 要写入的字符串 stream 这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符串的流。 返回值: 该函数返回一个非负值,如果发生错误则返回 EOF。
while (fgets(buffer, sizeof(buffer), from_fp != NULL)) { fputs(buffer, to_fp) memset(buffer, 0, sizeof(buffer)); }
五、fprintf(格式化输出)
文件里面没格式,需要自己去定义
头文件:#include 原型:int fprintf(FILE *stream, const char *format...) 功能:会根据参数format字符串来转换并格式化数据,然后将结果输出到参数stream指定的文件中,知道字符串结束(\0)为止 参数: stream 目标文件指针 format 这是 C 字符串,包含了要被写入到流 stream 中的文本。 返回值:如果成功,则返回写入的字符总数,否则返回一个负数。 fprintf详见:C 库函数 - fprintf
#include <stdio.h> int main(int argc, char const *argv[]) { int num = 5; char name[20] = "zhangsan"; int age = 16; FILE *fp = fopen(argv[1], "a+"); fprintf(fp, "%d:%s:%d\n", num, name, age); //sprintf // fwrite(&num, 1, sizeof(num), fp); // fseek(fp, 0, SEEK_SET); // int temp; // fread(&temp, 1, sizeof(temp), fp); fclose(fp); return 0; }
五、文件操作(stdin、stdout、stderr)
文件指针:
stdin(键盘)
stdout(终端)
stderr(终端)
char buffer[1024]; fgets(buffer,sizeof(buffer),stdin); //键盘上读取数据 buffer[strlen(buffer) - 1] = '\0'; fputs(buffer,stdout); 打印错误信息或者调试信息时,用stderr 打印正常信息时,用stdout
六、随机读取数据
二进制读取文件
#include <stdio.h> struct node { int num; char name[20]; int age; }; int main(int argc, char const *argv[]) { FILE *fp = fopen(argv[1], "ab+"); if (NULL == fp) { printf("error!"); exit(1) } struct node p1 = {.num = 1, .name = "zhangsan", .age = 16}; struct node p2 = {.num = 2, .name = "zhangsi", .age = 17}; struct node p3 = {.num = 3, .name = "zhangwu", .age = 18}; fwrite(&p1, 1, sizeof(p1),fp); fwrite(&p2, 1, sizeof(p1),fp); fwrite(&p3, 1, sizeof(p1),fp); fseek(fp, 0, SEEK_SET) fseek(fp, sizeof(struct node), SEEK_SET); struct node temp; fread(&temp, 1, sizeof(struct node),fp); printf("num = %d, name = %s, age = %d\n", temp.num, temp.name, temp.age); fclose(fp); return 0; }