【文件指针+文件顺序读写操作函数】
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
1.文件的打开和关闭
1.1 什么是文件指针
每个被使用的文件都在内存中开辟了一个相应的文件信息区用来存放文件的相关信息如文件的名
字文件状态及文件当前的位置等。这些信息是保存在一个结构体变量中的。该结构体类型是有系统
声明的取名FILE.
假如我们要操作一个文件名为text.txt 首先要打开文件打开文件的同时操作系统会自动为该文件创建一个文件信息区专门用来记录该文件的信息。
文件信息区的每一个信息与text.txt的信息是一一对应的。而该文件信息区名为struct _iobuf又被重命名为 FILE 。
所以FILE其实就是文件信息区。
每当打开一个文件的时候系统会根据文件的情况自动创建一个FILE结构的变量并填充其中的信息使用者不必关心细节。
一般都是通过一个FILE的指针来维护这个FILE结构的变量这样使用起来更加方便。
下面我们可以创建一个FILE*的指针变量:
FILE* pf; 文件指针变量
通过该文件指针变量我们就可以读写文件中的信息。
文件在读写之前需要打开文件
//打开文件
FILE * fopen ( const char * filename, const char * mode );
读写文件完成后需要关闭文件
//关闭文件
int fclose ( FILE * stream );
文件的打开方式如下
举个例子
#include <stdio.h>
int main ()
{
//打开文件
FILE* pFile = fopen ("text.txt","w");
//文件操作
if (pFile!=NULL)
{
fputs ("fopen",pFile);
//关闭文件
fclose (pFile);
}
return 0;
}
该段代码的意思是打开一个文件叫text.txt以写的形式打开。意味着向文件中写入信息。具体是怎么写的下面会讲到。
写完信息后关闭文件fclose(pFile)pFile就是一个文件指针。
文件指针就是用来操作文件的假如我们需要对文件进行写入的操作就使用文件指针打开该文件并定义"写"的操作。
2.文件操作函数
2.1 fgetc函数和fputc函数
fgetc函数和fputc函数是针对字符的输入输出的。
int fgetc(FILE* stream);
//从流中读取字符返回读到的ascii码值
流是什么呢可以把流理解成水流水流到尽头就是一个蓄水池。一个蓄水池就相当于一个存储大量文件的区域。文件也类似从流中文件信息区中读取文件fgetc返回读到的ascii码值。
int fputc(int character, FILE* stream);
//把字符character 写入流中
fputc是将一个字符写入文件中。一次写入一个字符返回成功写入的字符的个数。
举个例子
int main()
{
FILE* pf =fopen("text.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 0;
}
//写入字符
char ch = 0;
for (ch = 'a'; ch <= 'z'; ch++)
{
fputc(ch, pf);
}
fclose(pf);
pf = NULL;
return 0;
}
先打开text.txt文件如果不存在该文件则会新建一个文件"w"写入的形式会新建一个文件但是以"r"的形式打开文件如果文件不存在会读取文件失败返回NULL
然后向文件中写入a~z个字母。
运行成功成功写入文件
写入成功现在向文件中读取数据
int main()
{
FILE* pf = fopen("text.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 0;
}
//写入字符
char ch = 0;
for (ch = 'a'; ch <= 'z'; ch++)
{
int ch = fgetc(pf);
printf("%c ", ch);
}
fclose(pf);
pf = NULL;
return 0;
}
读取成功如下图
总结fgetc函数是向文件指针pf或者其他名字由你来定一次读取一个字符读取完第一个字符后指针自动跳到下一个字符。
fputc函数是向pf指向的指针一次写入一个字符。
2.2 fgets函数和fputs函数
int fputs(const char* str, FILE* stream);
向流中写入一行数据一次性写一行
举个例子
int main()
{
FILE* pf = fopen("text.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 0;
}
fputs("Hello World","w");
fclose(pf);
pf = NULL;
return 0;
}
写入成功。
注意打开文件进行写入操作时上一次写入的数据将会被清除。
接下来向从文件中读取数据
int main()
{
FILE* pf = fopen("text.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 0;
}
//读文件一次读一行
char buf[20];
fgets(buf, 10, pf); // 读10个字节相当于读9个最后一个字节留着放\0
printf("%s\n", buf);
fclose(pf);
pf = NULL;
return 0;
}
注意当我们读取10个字节时实际上打印出来只打印前面9个字节的内容还有一个字节是被用来留着放\0的。
还有一种情况假如我们需要读取20个字节的数据然而第一行不足20个字节fgets读完所有的数据后即使不够20个字节就不会再读取了就停止了。不会跳到第二行继续读。 更说明fges是一次只读取一行。
2.3 fscanf函数和fprintf函数
前面说过fscanf函数和fprintf函数是格式化输入输出函数。什么是格式化函数呢
其实格式化函数就是对于不同格式的数据都能够进行输入输出比如整型浮点型结构体类型等等这些就是不同格式的数据。
相较于scanf和printf函数fscanf函数和fprintf只是多了一个参数即FILE指针所指向的文件。fscanf函数是向FILE的指针指向的文件中读取格式化的数据fprintf函数是向FILE*的指针指向的文件中写入格式化的数据。
对比如下
int fscanf ( FILE * stream, const char * format, ... );
int scanf ( const char * format, ... );
int fprintf ( FILE * stream, const char * format, ... );
int printf ( const char * format, ... );
举一个简单的例子
向text.txt文件中写入结构体数据
int main()
{
FILE* pf = fopen("text.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 0;
}
struct S
{
char name[20];
int age;
float score;
}s = {"zhangsan",20,99.5f};
fprintf(pf,"%s %d %f", s.name, s.age, s.score);
fclose(pf);
pf = NULL;
return 0;
}
运行成功后文件中就有了该结构体的数据。
对于fscanf来说亦是如此
以读的方式打开该文件对其中的数据进行读取。读取后打印出来看即可。
s.name不用&的原因是s.name是一个数组名表示首元素地址不需要&而其他的age和score则需要&。
前面说过这几个函数都是适用于所有输入流输出流那么就包括了键盘标准输入流屏幕标准输出流。
int main()
{
int ch = fgetc(stdin);
fputc(ch, stdout);
}
此时我们会从键盘中读取一个字符写入到屏幕中。
对于其他函数也是如此。仍可以从键盘中读取数据写入到屏幕上。
2.4 fwrite函数和fread函数
上面提到fwrite函数和fread函数是以二进制的形式进行写入和读取的。
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
先来看看fwrite在库中的声明。
fwrite函数是向stream这个流中一次写count个大小为size的ptr指向的内容。
看不懂没关系举个例子
typedef struct S
{
char name[20];
int age;
float score;
}S;
int main()
{
S s = { "zhangsan",20,95.5f };
FILE* pf = fopen("text.txt", "wb");
if (pf == NULL)
{
perror("fopen");
return 0;
}
fwrite(&s, sizeof(S), 1, pf);
fclose(pf);
pf = NULL;
return 0;
}
此时我们创建了一个结构体该结构体有三个成员我们以二进制写入的形式打开文件进行写入此时向pf指向的文件中写入s这块空间一次写入1个sizeof(S)大小的内容。
运行成功后打开text.txt文件
你会发现出了拼音zhangsan其他的都看不懂没关系因为这是二进制形式。
看不懂并不代表代码是错误的。
既然我们看不懂我们就让编译器来看下面我们以二进制读取的方式向文件中读取数据出来。
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
既然是读取那么就是跟写入相反而已。
从stream流指向的文件中读取ptr这块空间的内容一次读取count个大小为size个字节的内容。
typedef struct S
{
char name[20];
int age;
float score;
}S;
int main()
{
S s = { 0 };
FILE* pf = fopen("text.txt", "rb");
if (pf == NULL)
{
perror("fopen");
return 0;
}
fread(&s, sizeof(S), 1, pf);
printf("%s %d %f", s.name, s.age, s.score);
fclose(pf);
pf = NULL;
return 0;
}
此时我们向pf流指向的文件中读取s这块空间的内容一次读取1个大小为sizeofS个字节的内容。读取成功后我们就打印出来看看。
打印结果确实符合预期。
总结fwrite 和fread函数是向文件中以二进制的形式写入和读取文件的。