C语言-文件操作2
fread和fwrite函数的用法
fscanf和fprintf函数的用法
rewind和fseek函数的用法
fgets函数有局限性,每次只能读一行数据,因为fgets函数遇到换行符就结束读取,如果希望读取多行数据,需要使用fread函数;相应的写入函数为fwrite函数。
对于Windows 系统,使用fread()和fwrite()时应该以二进制的形式打开文件,之所以这样,是因为:
-
Windows 平台中,程序中是 “\n”,对应的文件内容是 “\r\n”;而二进制文件的写入和读取按其原样。例:定义 fp 是 Windows 平台中以文本文件形式打开的文件指针,则 fprintf(fp, “\n”); 运行后,文件中多了 “\r\n”。
-
Mac 平台中,程序中是 “\n”,对应的文件内容是 “\n\r”;而二进制文件的写入和读取按其原样。例:定义 fp 是 Mac 平台中以文本文件形式打开的文件指针,则 fprintf(fp, “\n”); 运行后,文件中多了 “\n\r”。
-
Linux 平台中,文本文件和二进制文件没有任何区别。
fread函数用来从指定文件中读取块数据,所谓块数据,也就是若干个字节的数据,可以是字符,可以是字符串,可以是多行数据,并没有什么限制: fread()
size_t fread(void *ptr, size_t size, size_t count, FILE *fp);
fwrite()
size_t fwrite(void *ptr, size_t size, size_t count, FILE *fp);
参数说明:
- ptr为内存区块的指针,它可以是数组、变量、结构体等。fread()中的ptr用来存放读取到的数据,fwrite()中ptr用来存放要写入的数据。
- size:表示每个数据块的的字节数
- count: 表示要读写的数据块块数
- fp:表示文件指针
- 理论上,每次读写size*count个字节的数据
size_t实在stdio.h和stdlib.h头文件中使用typedef定义的数据类型,表示无符号整数,也即非负数,常量用来表示数量。
返回值:返回成功读写的块数,也即count。如果返回值小于count:
- 对于fwrite()来说,肯定发生了写入错误,可以用ferror()函数检测。
- 对于fread()来说,可能读到了文件末尾,可能发生了错误,可以用ferror()或feof()检测。
数据写入完毕后,位置指针在文件的末尾,想要读取数据,必须将文件指针移动到文件开头,这就是rewind(fp);的作用。
文件后缀也可以不是.txt,它可以是任意的,你可以自己命名。
#include <stdio.h>
#define N 2
struct stu{
char name[10];//姓名
int num;//学号
int age;//年龄
float score;//成绩
}boya[N], boyb[N], *pa, *pb;
int main(){
FILE *fp;
int i;
pa = boya;
pb = boyb;
if((fp = fopen("D:\\demo.txt", "wb+")) == NULL){
puts("Fail to open file");
exit(0);
}
puts("Input data:\n");
for(i=0; i<N; i++,pa++){ //将数据填入结构体
scanf( " %s, %d, %d, %f " , pa->name, &pa->num, &pa->age, &pa->score);
}
//将结构体类型数组boya中的数据存入文件中
fwrite(boya, sizeof(struct stu), N, fp);
//判断写入是否成功
if(ferror(fp))
puts("写入错误");
else
puts("写入成功");
//将文件指针重置到文件开头
rewind(fp);
//将文件中的内容输出到结构体数组boyb中
fread(pb, sizeof(struct stu), N, fp)
//判断读取是否成功
if(ferror(fp))
puts("读取错误");
else
puts("读取成功");
for(i = 0; i < N; i++, pb++){
printf("%s, %d, %d, %f", pb->name, pb->num, pb->age, pb->score);
}
fclose(fp);
return 0;
}
运行结果:
Input data:
Tom 2 15 90.5↙
Hua 1 14 99↙
Tom 2 15 90.500000
Hua 1 14 99.000000
fscanf()函数和fprintf()函数的用法
fscanf()和fprintf()函数与前面使用的scanf和printf函数相似,都是格式化读写函数,两者的区别在于fscanf()和fprintf()目标不是显示器,而是文件。
int fprintf(FILE *fp, char *format, ...);
int fscanf(FILE *fp, char *format, ...);
fp为文件指针,format为格式控制字符串,……表示参数列表。与格式化输入输出并没有什么不同,只是多了一个文件指针fp。
- fprintf()返回成功写入的字符个数,失败则返回负数。
- fscanf()返回成功参数列表中被成功赋值的参数个数。
#include <stdio.h>
#define N 2
struct stu{
char name[10];
int num;
int age;
float score;
}boya[N], boyb[N], *pa, *pb;
int main(){
FILE = *fp;
int i;
pa = boya;
pb = boyb;
if((fp = fopen("D:\\demo.txt", "w+")) == NULL){
puts("Fail to open file!");
exit(0);
}
puts("Input data:\n");
//从键盘上输入数据输入到结构体类型数组boya中
for(i=0; i<N; i++,pa++){
scanf(" %s, %d, %d, %f" ,pa->name, &pa->num, &pa->age, &pa->score);
}
//把pa的指针重新指向boya的第一个字符
pa = boya;
//将boya中的数据输入到文件中
for(i=0; i<N; i++,pa++){
fprintf(fp, " %s, %d, %d, %f" ,pa->name, pa->num, pa->age, pa->score);
}
//将文件中的数据取出放到结构体类型数组boyb中
for(i=0; i<N; i++,pb++){
fscanf(fp, " %s, %d, %d, %f" ,pb->name, &pb->num, &pb->age, &pb->score);
}
pb = boyb;
//将结构体类型数组boyb中的数据输出到显示器上
for(i=0; i<N; i++,pb++){
printf(" %s, %d, %d, %f" ,pb->name, pb->num, pb->age, pb->score);
}
fclose(fp);
return 0;
}
随机读写文件
我在前面介绍的文件读写函数都是顺序读写,即从头开始,依次读写各个数据。但实际开发中经常需要读写文件的中间部分,要解决这个问题,就得先移动文件内部的指针,再进行读写,这种读写方式称为随机读写,也就是说从文件任意位置开始读写。
实现随机读写的关键在于,移动文件内部的位置指针,这称为文件的定位。
文件定位函数rewind和fseek
移动文件内部位置指针的函数主要有两个:
- rewind()用来将位置指针移动到文件开头,前面已经多次使用:
void rewind(FILE *fp);
- fseek()用来将位置指针移动到任意位置:
int fseek( FILE *fp, long offset, int origin);
参数说明:
- fp为文件指针,也就是被移动的文件。
- offset为偏移量,也就是要移动的字节数。之所以是long类型,是希望移动的范围足够大,能处理的文件更大。offset为正时,向后移动;offset为负时,向前移动。
- origin为起始位置,也就是从何处开始计算偏移量。C语言规定起始位置有三种,分别为文件开头、当前位置和文件末尾,每个位置都用对应的常量来表示:
起始点 | 常量名 | 常量值 |
---|---|---|
文件开头 | SEEK_SET | 0 |
当前位置 | SEEK_CUR | 1 |
文件末尾 | SEEK_END | 2 |
fseek函数一般用于二进制文件,在文本文件中由于要进行转换,计算的位置有时会出错。
文件的随机读写
在移动位置指针之后,就可以用前面介绍的任何一种读写函数进行读写了。由于是二进制文件,因此常用fread()和fwrite()读写。
#include <stdio.h>
#define N 3
struct stu{
char name[10];
int num;
int age;
float score;
}boys[N], boy, *pboys;
int main(){
FILE *fp;
int i;
pboys = boys;
if((fp = fopen("D:\\demo.txt", "wb+")) == NULL){
puts("Cannot open file, press any key to exit");
getch()
exit(1);
}
puts("Input data:");
for(i=0; i<N; i++,pboys++){
scanf(" %s %d %d %f", pboys->name, &pboys->num, &pboy->age, &pboy->score);
}
fwrite(boys, sizeof(struct stu), N, fp);
fseek(fp, sizeof(struct stu), 0);
fread(&boy,sizeof(struct stu), 1, fp);
printf("%s %d %d %f", boy.name, boy.num, boy.age, boy.score);
fclose(fp);
return 0;
}