1.文件基本概念
2.
2.打开关闭及读写文件
接下来,我们通过代码实现对文件的读写:
自选目录新建两个.txt文件:
其中gushi.txt中有如下内容,而gushi2.txt是空的:
接下来,我们通过代码来实现将gushi.txt中的内容写入到gushi2.txt中。
代码如下:
#include <stdio.h>
#include <stdlib.h>
int main(void){
char name[100] = "D:\\Desktop\\c-learningnotes\\part10\\2.test\\gushi.txt"; //char name[50] = "D:/Desktop/c-learningnotes/part10/2.test/gushi.txt"等价
FILE * fp = fopen(name, "r");
if(fp == NULL){
printf("文件打开失败,程序退出\n");
exit(-1);
}
FILE * fp2 = fopen("D:\\Desktop\\c-learningnotes\\part10\\2.test\\gushi2.txt", "w");
if(fp2 == NULL){
printf("文件打开失败,程序退出\n");
exit(-1);
}
char ch;
while((ch = fgetc(fp)) != EOF)
fputc(ch,fp2);
fclose(fp);
fclose(fp2);
return 0;
}
执行结果如下:
打开gushi2.txt,发现文件内容被成功写入:
3.向文件读写一个字符串
这里涉及两个函数:fgets函数和fputs函数
自选目录新建一个txt文件,内容如下:
代码如下:
#include <stdio.h>
#include <stdlib.h>
int main(void){
char a[10];
FILE * fp = fopen("D:\\Desktop\\c-learningnotes\\part10\\3.test\\78.txt", "r");
if(fp == NULL){
printf("打开文件失败,程序退出\n");
exit(-1);
}
//把D:\\Desktop\\c-learningnotes\\part10\\3.test\\78.txt 读进来输出到屏幕上
fgets(a, 10, fp); //程序第一次调用该句,a数组的内容为"123456\n",读到换行符时,fgets函数结束读入
fputs(a, stdout);
fgets(a, 10, fp); //程序第二次调用该句,a数组的内容为"123456789",读到最大容纳的有效字符的个数9时,fgets函数结束读入
fputs(a, stdout);
fgets(a, 10, fp); //程序第三次调用该句,a数组的内容为"abcdefg" ,读到文件末尾时,fgets函数结束读入
fputs(a, stdout);
putchar('\n');
//把从键盘上输入的数据使用fgets和fputs输出到屏幕上
while(fgets(a, 10, stdin) != NULL) //在windows系统下 在新的一行上(切记)按下ctrl+z+回车 就会输入文件结束标志EOF
fputs(a, stdout);
fclose(fp);
fp = NULL; //最好使一个使用完的指针的值为NULL,这样可以避免野指针的出现
return 0;
}
执行结果如下:
4.用格式化的方式读写文件
要读的4.txt文件内容如下:
代码如下:
#include <stdio.h>
#include <stdlib.h>
int main(void){
FILE * p1 = fopen("D:\\Desktop\\c-learningnotes\\part10\\4.test\\4.txt", "r");
if(p1 == NULL){
printf("文件打开失败,程序退出\n");
exit(-1);
}
FILE * p2 = fopen("D:\\Desktop\\c-learningnotes\\part10\\4.test\\4-1.txt","w");
if(p2 == NULL){
printf("文件打开失败,程序退出\n");
exit(-1);
}
int a;
double b;
char c[40];
fscanf(p1, "%d%lf%s", &a, &b, c);
fprintf(p2, "%d\n%.1lf\n%s\n", a, b, c);
fclose(p1);
fclose(p2);
p1 = NULL;
p2 = NULL;
return 0;
}
执行结果如下:
文件4-1.txt中被写入内容:
5.用二进制的方式读写数据
代码如下:
#include <stdio.h>
#include <stdlib.h>
typedef struct{
char name[30];
double score;
}Stu;
int main(void){
Stu a[3] = {{"zhangsan", 89.5},{"lisi", 78},{"wangwu", 90.1}};
FILE * p1 = fopen("D:\\Desktop\\c-learningnotes\\part10\\5.test\\5.abc", "wb");
if(p1 == NULL){
printf("文件打开失败,程序退出\n");
exit(-1);
}
fwrite(a,sizeof(Stu), 3, p1);
fclose(p1);
p1 = fopen("D:\\Desktop\\c-learningnotes\\part10\\5.test\\5.abc","rb");
if(p1 == NULL){
printf("文件打开失败,程序退出\n");
exit(-1);
}
Stu b[3];
fread(b, sizeof(Stu), 3, p1);
for(int i = 0; i < 3; ++i){
printf("第%d个学生的姓名:%s,成绩:%.1lf\n", i+1, b[i].name, b[i].score );
}
fclose(p1);
return 0;
}
执行结果如下:
6.文件读写的注意事项
通过代码来验证这句话:
要读取的文件内容如下:
代码如下:
#include <stdio.h>
#include <stdlib.h>
int main(void){
FILE * p = fopen("D:\\Desktop\\c-learningnotes\\part10\\6.test\\6.txt", "rb");
//打开方式为r时,输出3个ASCII码值,如果打开方式为rb,输出4个ASCII码值
if(p == NULL){
printf("文件打开失败,程序退出\n");
exit(-1);
}
char ch;
while((ch = fgetc(p)) != EOF)
printf("%d\n", ch);
fclose(p);
return 0;
}
/*
在windows系统下,使用fputc,fputs,fprintf向一个文件写入数据时,如果写入'\n',
文件的打开方式为文本模式,实际写入的是'\r'和'\n'两个字符;如果文件的打开方式
为二进制模式,实际就是写入一个'\n'字符。
使用fgetc,fgets,fscanf向一个文件读入数据时,如果读到'\r'和'\n',而且文件打
开方式为文本模式的时候,会把这两个字符当成一个'\n'读进来; 如果文件的打开方式
为二进制模式,那么不会发生这种转换,读进来的就是'\r'和'\n'两个字符
建议:如果文件本身是一个文本文件,就用文件模式的文件使用方式打开,对这个文件
进行读写就用这6个处理字符或者字符串的函数进行读写。
*/
执行结果如下:
7.整型是如何存储在内存当中的
代码如下:
#include <stdio.h>
typedef union{
int a;
char b[4];
}A;
int main(void){
A c;
c.b[0] = 'A';
c.b[1] = 'B';
c.b[2] = 'C';
c.b[3] = 'D';
printf("%d\n", c.a ); //68×2^24+67×2^16+66×2^8+65=1145258561 整型数据在内存中是低位在前,高位在后的
return 0;
}
行结果如下:
8.文件读写注意事项2
代码如下:
#include <stdio.h>
#include <stdlib.h>
typedef struct{
int a;
int b;
}A;
int main(void){
A c;
fread(&c, sizeof(A), 1, stdin); //stdin属于标准流文件的一种,凡是标准流文件的使用方式都是“文本模式”,所以这里就会发生字符转换
printf("%d, %d\n", c.a, c.b );
return 0;
}
/*
输入1234按回车
再输入1234按回车
输出:
875770417, 858927370
a = 52*2^24+51*2^16+50*2^8+49
b = 51^2^24+50*2^16+49*2^8+10
建议:对二进制文件进行读写时用fread和fwrite函数,文本文件最好不要用这两个函数进行读写
*/
执行结果如下:
9.rewind函数
下面我们通过代码示例来理解:
在指定目录下中,有一个9.txt文件,其中有如下内容:
而程序的功能是,让用户通过键盘把数据存放到指定目录下的指定文件末尾,最后再把这个稳健的所有内容输出到屏幕上。
代码如下:
//程序功能:让用户通过键盘把数据存放到指定目录下的指定文件末尾,最后再把这个稳健的所有内容输出到屏幕上
#include <stdio.h>
#include <stdlib.h>
int main(void){
FILE * p = fopen("D:\\Desktop\\c-learningnotes\\part10\\9.test\\9.txt","a+");
if(p == NULL){
printf("文件打开失败,程序退出\n");
exit(-1);
}
char ch;
while((ch = getc(stdin)) != EOF){
putc(ch ,p);
}
rewind(p);
while((ch = getc(p)) != EOF){
putc(ch, stdout);
}
fclose(p);
return 0;
}
执行结果如下:
10.fseek函数
代码如下:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char name[30];
double score;
}A;
FILE * create(void);
void show(FILE * p);
int length(FILE * p);
bool insert(FILE * p, int index);
void sort(FILE * p);
int main(void){
FILE * p = create();
// insert(p,2);
sort(p);
show(p);
fclose(p);
return 0;
}
FILE * create(void){
FILE * p = fopen("D:\\Desktop\\c-learningnotes\\part10\\10.test\\10.abc","wb+");
if(p == NULL){
printf("文件打开失败,程序退出\n");
exit(-1);
}
int n;
A b;
printf("请输入学生数:\n");
scanf("%d", &n);
for(int i = 0; i < n; ++i){
printf("请输入第%d个学生的姓名和成绩:\n", i+1);
scanf("%s%lf", b.name, &b.score);
fwrite(&b, sizeof(A), 1, p);
}
return p;
}
void show(FILE * p){
fseek(p, 0L, 0); // rewind(p); 与其等价
A b;
while(fread(&b, sizeof(A), 1, p) == 1)
printf("学生姓名:%s,成绩:%lf\n", b.name, b.score);
}
int length(FILE * p){
fseek(p, 0L, 2);
return ftell(p)/sizeof(A);
}
bool insert(FILE * p, int index){
int len = length(p);
if(index < 1 || index > len+1)
return false;
A b;
for(int i = len-1; i >= index-1; --i){
fseek(p, i*sizeof(A), 0);
fread(&b, sizeof(A), 1, p);
fseek(p, (i+1)*sizeof(A), 0);
fwrite(&b, sizeof(A), 1, p);
}
printf("请输入所要插入的学生的姓名和成绩:\n");
scanf("%s%lf", b.name, &b.score);
fseek(p, (index-1)*sizeof(A), 0);
fwrite(&b, sizeof(A), 1, p);
return true;
}
void sort(FILE * p){
int len = length(p);
for(int i = 0; i < len-1; ++i){
for(int j = 0; j < len-1-i; ++j){
A b1, b2;
fseek(p, j*sizeof(A), 0);
fread(&b1, sizeof(A), 1, p);
fread(&b2, sizeof(A), 1, p);
if(b1.score > b2.score){
fseek(p, j*sizeof(A), 0);
fwrite(&b2, sizeof(A), 1, p);
fwrite(&b1, sizeof(A), 1, p);
}
}
}
}
执行结果如下:
11.文件读写检测概念及错误应用
代码如下:
#include <stdio.h>
#include <stdlib.h>
int main(void){
FILE * p = fopen("D:\\Desktop\\c-learningnotes\\part10\\11.test\\11.txt","r"); //该文件没有内容
if(p == NULL){
printf("文件打开失败,程序退出\n");
exit(0);
}
if(!feof(p)) //错误的使用feof判断文件有没有内容,文件结束和错误标志使用fopen函数后自动设置为0,所以这个时候使用feof或者ferror函数的返回值没有任何意义
printf("这个文件有内容\n");
else
printf("这个文件没有内容\n");
printf("%d\n", ferror(p)); //输出0
fclose(p);
return 0;
}
执行结果如下:
12.文件读写检测正确应用
在指定目录下,有一个12.txt,其内容为:
代码如下:
#include <stdio.h>
#include <stdlib.h>
void ce(FILE * p){ //建议大家,每当对文件进行I/O操作之后就要检测有没有读写错误,如果有就把错误这个错误清除
if(ferror(p)){
printf("文件读写出错\n");
clearerr(p);
}
}
int main(void){
FILE * p = fopen("D:\\Desktop\\c-learningnotes\\part10\\12.test\\12.txt","r");
if(p == NULL){
printf("文件打开失败,程序退出\n");
exit(0);
}
putc('A',p);
ce(p);
printf("%d\n", ferror(p)); //输出0,因为clearerr会把文件结束标志设置为0,即清除读写错误
/*
char ch;
while((ch = getc(p)) != EOF) //getc函数会在读入出错或者读到文件末尾的时候返回EOF,所以如果文件产生读写错误,则很有可能不会把p所指向的稳健的全部内容读进来
putchar(ch);
*/
while(!feof(p)){ //此种做法可以把文件中的全部内容读进来输出到屏幕上,只不过末尾会多输出一个值为EOF的文件结束符
putchar(getc(p));
ce(p);
}
printf("%d\n", feof(p)); //输出一个非0值,因为读写到达文件的末尾
clearerr(p);
printf("%d\n", feof(p)); //输出0,因为clearerr会把文件的结束设置为0
fclose(p);
return 0;
}
执行结果如下:
13.文件读写注意事项3
在指定目录下,有一个13.txt,其内容为:
代码如下:
#include <stdio.h>
#include <stdlib.h>
int main(void){
FILE * p = fopen("D:\\Desktop\\c-learningnotes\\part10\\13.test\\13.txt", "r+");
if(p == NULL){
printf("文件打开失败,程序退出\n");
exit(-1);
}
putchar(getc(p)); //文件的读写是分时进行的,不能一会读一会写,反之也不可以。该语句使得文件标记处于读的状态,所以不能进行写的操作,可以使用rewind或者fseek函数解除文件标记的状态锁定,以便进行后面的读写
// rewind(p); //可以把这两句去掉注释,然后对比88.txt的内容差别
// fseek(p, 1L, 0);
putc('A', p);
fclose(p);
}
//建议:尽量不要对一个文件既读又写,非常容易出错