目录
一、文件概述
1.存储角度
文件存取方式分为:顺序存取方式、随机存取方式。
- 顺序存取就是从上往下,写入数据时,将数据附加在文件的末尾。常用于文本文件。
- 随机存取方式多半以二进制文件为主。
2.文件类型
文件类型分为:文本文件和二进制文件
- 文本文件是以字符编码的方式进行保存的。
- 二进制文件将内存中的数据原封不动的进行保存,适用于非字符为主的数据。
3.文件操作流程
建立/打开文件——从文件中读取数据或向文件中写数据——关闭文件
- 当一个文件不存在时,如果是读操作,则会报错。
- 当一个文件不存在时,如果是写操作,则会自动创建这个文件。
- 文件打开和关闭是成套的,当结束使用之后一定要关闭文件,
#include <stdio.h> #include <stdlib.h> // 为了使用EXIT_FAILURE int main() { FILE *p = fopen("/tmp/1.txt", "r"); if (p == NULL) { printf("open error!\n"); return 0: } fclose(p); // 成功打开文件后关闭它 return 0; // 程序成功执行 }
二、文件的基本操作
1.文件的使用模式
1、“r”(只读):从文件头开始
- 文本文件需存在,如不存在则报错。
2、“r+”(读写):从文件头开始
- 文本文件需存在,如不存在则报错。
3、“w”(只写):从文件头开始
- 文本文件不存在则创建新文件,存在则清空原有内容。
4、“w+”(读写):从文件头开始
- 文本文件不存在则创建新文件,存在则清空原有内容。
5、“a”(追加)(读写):从文件尾开始
- 文本文件不存在进行创建新文件,存在则在末尾追加。
6、“a+” (追加)(读写):从文件头读取,从文件尾写入
- 文本文件不存在进行创建新文件,存在则在末尾追加。
二进制使用模式同上面所示,唯一就是在后面加上“b”即可,如下所示:
1、“rb”(只读):从文件头开始
- 二进制文件需存在,如不存在则报错。
2、........均类比如上
2.文件字符形式的输入输出
1、函数fgetc()、fputc()
- fgetc(fp_read):从fp指向的文件读入一个字符,若失败返回EOR即-1。
- fputc(ch, fp_write):将字符ch写到fp指向的文件,若失败返回EOR即-1。
#include <stdio.h> #include <stdlib.h> int main() { FILE *fp_read, *fp_write; char ch, fir_name[40], sec_name[40]; printf("请输入被复制的文件名: "); scanf("%s", fir_name); printf("请输入新的文件名: "); scanf("%s", sec_name); // 打开源文件进行读取 if (!(fp_read = fopen(fir_name, "r"))) { printf("Cannot open the file %s!\n", fir_name); return 1; // 返回非零值表示错误 } // 打开目标文件进行写入 if (!(fp_write = fopen(sec_name, "w"))) { printf("Cannot open the file %s!\n", sec_name); fclose(fp_read); // 发生错误时关闭已打开的源文件 return 1; // 返回非零值表示错误 } // 逐字符读取源文件并写入目标文件 while ((ch = fgetc(fp_read)) != EOF) { fputc(ch, fp_write); } printf("Copy complete!\n"); // 关闭文件 fclose(fp_read); fclose(fp_write); return 0; // 程序正常结束 }
3.文件字符串形式的输入输出
1、函数fgetc()、fputc()
- fgets(str, 100, fp_read):从fp指向的文件读入长度(100-1)字符并保存在str字符数组中,若失败返回NULL。
- fputs(str, fp_write):将tr字符数组内容写入fp_write指向的目标文件 ,成功返回0,若失败返回非0值。
#include <stdio.h> #include <stdlib.h> int main() { FILE *fp_read, *fp_write; char str[100]; // 增加缓冲区大小,以便能够读取更长的行 // 打开源文件进行读取 if (!(fp_read = fopen("text.txt", "r"))) { // 注意修正双引号的使用 printf("Cannot open the file text.txt!\n"); return 1; // 返回非零值表示错误 } // 打开目标文件进行写入(假设目标文件名为 copy.txt) if (!(fp_write = fopen("copy.txt", "w"))) { printf("Cannot open the file copy.txt!\n"); fclose(fp_read); //发生错误时关闭已打开的源文件 return 1; // 返回非零值表示错误 } // 逐行读取源文件并写入目标文件 while (fgets(str, 100, fp_read)) { // 注意 fgets 函数的调用方式 printf("%s", str); fputs(str, fp_write); // 将读取的内容写入fp_write指向的目标文件 } printf("Copy complete!\n"); // 关闭文件 fclose(fp_read); fclose(fp_write); return 0; // 程序正常结束 }
4.文件格式化形式的输入输出
1、函数fscanf()、fprintf()(不建议用,推荐使用fread和fwrite)
- fscanf(fp,格式串,输入项表):从文本文件中按格式输入数据,成功时,返回成功匹配并赋值的输入项数;如果到达文件末尾或发生读取错误,则可能返回EOF。
- fprintf(fp,格式串,输出项表):按格式输出数据到文本文件中。
#include <stdio.h> #include <string.h> int main() { FILE *file = fopen("./1.txt", "r"); if(file == NULL) { printf("open error!\n"); return 0; } FILE *fp = fopen("./2.txt", "w"); char buf[1024] = {0}; fscanf(file, "%s", buf); fprintf(fp, "aaa:%s", buf); fclose(file); fclose(fp); return 0; }
5.文件数据块形式的输入输出
1、函数read(buffer,size,count,fo)、fwrite(buffer,size,count,fp):
2、buffer:是一个地址。(起始地址)
- 对fread来说:用来存放文件读入的数据的存储区的地址;
- 对fwrite来说:把此地址开始的存储区中的数据向文件输出。
3、size:要读写的字节数。
4、count:要读写多少个数据项。(每个数据项长度为size)
5、fp:FILE 类型指针
注意:数据块输入输出函数只适合于二进制文件#include <stdio.h> #define SIZE 10 struct student { char name[20]; int num; int age; char addr[20]; } stu[SIZE]; int main() { int i; FILE *fp_read, *fp_write; if (!(fp_read = fopen("data stu.dat", "rb"))) { printf("Cannot open the file data stu.dat!\n"); return 0; } if (!(fp_write = fopen("datal stu.dat", "wb"))) { printf("Cannot open the file datal stu.dat!\n"); fclose(fp_read); //发生错误时关闭已打开的源文件 return 0; } for (i = 0; i < SIZE; i++) { if (fread(&stu[i], sizeof(struct student), 1, fp_read) != 1) { printf("File read error\n"); fclose(fp_read); fclose(fp_write); return 0; } printf("Name: %s, Num: %d, Age: %d, Addr: %s\n", stu[i].name, stu[i].num, stu[i].age, stu[i].addr); if (fwrite(&stu[i], sizeof(struct student), 1, fp_write) != 1) { printf("File write error\n"); fclose(fp_read); fclose(fp_write); return 0; } } printf("Successful storage!\n"); fclose(fp_read); fclose(fp_write); return 1; }
6.文件的随机读写
1、文件的随机读写:指定想要读写的文件位置。
2、rewind(fp)函数
- rewind():函数使文件文件位置标记指向文件开头。
- rewind(pf)
3、fseek(fp,位移量,起始点):改变文件位置标记
- 文件起始点含义如下:
文件开头 SEEK_SET = 0 当前位置 SEEK_CUR = 1 文件结尾 SEEK_END = 2
- 位移量:这个值可以是正数、负数或零。正数表示向前移动(远离文件开头),负数表示向后移动(朝向文件开头),零则不移动位置但可以用来重新定位起始点。
fseek(fp,100L,0);//将文件位置标记向前移到离文件开头100个字节处 fseek(fp,50L,1); //将文件位置标记前移到离当前位置50个字节处 fseek(fp,-10L,2);//将文件位置标记从文件末尾处向后退10个字节
4、代码实现
#include <stdio.h> #define SIZE 10 // 定义学生结构体 struct student { char name[20]; int num; int age; char addr[20]; };stu[SIZE]; int main() { FILE *fp_read, *fp_write; int i; // 打开文件以写入,注意文件名和模式 if (!(fp_write = fopen("data_stu.txt", "wb"))) { printf("Cannot open the file data_stu.txt for writing!\n"); return 1; } // 打开文件以读取 if (!(fp_read = fopen("data_stu.dat", "rb"))) { printf("Cannot open the file data_stu.dat for reading!\n"); fclose(fp_write); // 关闭已打开的文件 return 1; } printf("Name\tNum\tAge\tAddr\n"); for (i = 0; i < SIZE; i += 2) { fseek(fp_read,i*sizeof(struct student),0); fread(&stu[i], sizeof(struct student), 1, fp_read); fwrite(&stu[i], sizeof(struct student), 1, fp_write); printf("%s\t%d\t%d\t%s\n", stu[i].name, stu[i].num, stu[i].age, stu[i].addr); } fclose(fp_read); fclose(fp_write); printf("Successful storage!\n"); return 0; // 成功返回0 }