目录
5.1 fseek函数:根据文件指针的位置和偏移量来定位文件指针
预备知识:
1.磁盘文件和内存文件;(是否被进程打开了)
2. 程序文件和数据文件;
程序文件包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀 为.exe);
数据文件包括程序运行时读写的数据
3. 文本文件和二进制文件;
数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。
如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件。

FILE * pf ; // 文件指针变量
定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联的文件。
如何理解标准输出流和标准输入流:
stdin标准输入流:从键盘上输入
stdout标准输出流:输出(打印)到屏幕上
stdin和stdout都是文件指针变量(FILE*类型),一个程序默认打开的两个流设备。输入输出都是相对于程序来说的
int ch = fgetc(stdin);//从键盘输入
fputc(ch,stdout);//输出到屏幕
FILE * fopen ( const char * filename, const char * mode );//打开文件,返回一个文件指针,参数是文件路径+文件名、打开的模式
文件路径+文件名有两种方式
a.相对路径
.. 表示上一级路径(相对于此代码test.c来说的)
. 表示当前路径(此代码test.c所在的文件路径下)
fopen("..\\test.txt", "wb");//上一级
fopen(".\\test.txt", "wb");//或者直接fopen("test.txt", "wb");//这两种是一样的
b.绝对路径
E:\\Desktop\\xuexi\\02_ccccc\\test_20220430_file\\test_20220430_file\\test.txt
绝对路径里面要加两个\\,其中一个用于转义;或者用/
- FILE * pf = fopen("test.txt", "w");//r只读 w只写 a追加
- if(pf == NULL)
- {//打开失败
- printf("%s\n", strerror(errno));
- }
- //打开成功
-
- fclose(pf);
- pf = NULL;


- //写入文件
- FILE* pf = fopen("zhu.txt", "w");
- if(pf != NULL){
- fputc('b', pf);
- fputc('a', pf);
- fputc('c', pf);
- fclose(pf);//使用结束关闭文件
- pf = NULL;
- }
- //从文件里面读
- FILE* pf = fopen("zhu.txt", "r");
- if(pf != NULL){
- printf("%c\n", fgetc(pf));//fgetc每次读取一个字符
- printf("%c\n", fgetc(pf));//会自动读下一个
- printf("%c\n", fgetc(pf));
- fclose(pf);
- pf = NULL;
- }
- //int fputs( const char *string, FILE *stream );
- //char *fgets( char *string, int n, FILE *stream );
- //写到文件
- FILE* pf = fopen("zhu.txt", "w");
- if(pf != NULL)
- {
- fputs("hello\n",pf);//换行需要自己添加
- fputs("zzz",pf);
-
- fclose(pf);
- pf = NULL;
- }
- //下面从文件里面读取
- char buf[1024] = {0};
- FILE* pf = fopen("zhu.txt", "r");
- if(pf != NULL)
- {
- fgets(buf, 1024, pf);
- printf("%s", buf);//这里面会主动换行(因为原来文本里hello后面有一个换行),不用加\n
- fgets(buf, 1024, pf);
- //printf("%s", buf);//但是zzz后面没有换行
- puts(buf);//但是puts函数天生会自带一个换行
-
- fclose(pf);
- pf = NULL;
- }
char ch[1024] = {0};
fgets(ch, 1024, stdin);//从键盘读取
fputs(ch, stdout);//输出到屏幕
//以上等价于下面的
//gets(ch);
//puts(ch);
int printf( const char *format [, argument]... );
int fprintf( FILE *stream, const char *format [, argument ]...);
fprintf相当于printf只多了一个FILE *stream,也就是输出的流
- //写入文件
- struct S s = {100, 3.14, "bit"};
- FILE* pf = fopen("test.txt", "w");
- if(pf != NULL)
- {
- fprintf(pf, "%d %f %s\n", s.n ,s.score, s.arr);
- fclose(pf);
- pf = NULL;
- }
- //从文件中读取
- struct S s = {0};
- FILE * pf = fopen("test.txt", "r");
- if(pf != NULL)
- {
- fscanf(pf, "%d %f %s", &s.n, &s.score, s.arr);
- printf("%d %f %s", s.n, s.score, s.arr);
-
- fclose(pf);
- pf = NULL;
- }
同样,fprintf和fscanf函数也适用于标准输入输出流(键盘和屏幕)
scanf/fscanf/sscanf
printf/fprintf/sprintf
- //sprintf,把格式化数据转换成字符串
- struct S s = {100, 3.14, "abcd"};
- struct S tmp = {0};
- char buf[1024] = {0};
- sprintf(buf, "%d %f %s", s.n, s.score, s.arr);
- printf("%s\n", buf);
- //sscanf,从字符串中读取格式化数据
- sscanf(buf, "%d %f %s", &tmp.n, &tmp.score, tmp.arr);
- printf("%d %f %s", tmp.n, tmp.score, tmp.arr);
size_t fread(void*buffer,size_t size,size_t count,FILE*stream);
1.buffer: 是读取的数据存放的内存的指针,
(可以是数组,也可以是新开辟的空间)
ps: 是一个指向用于保存数据的内存位置的指针(为指向缓冲区
保存或读取的数据或者是用于接收数据的内存地址)
2.size: 是每次读取的字节数
3.count: 是读取的次数
4.stream: 是要读取的文件的指针
ps: 是数据读取的流(输入流)
size_t fwrite(void*buffer,size_ size,size_t count,FILE*stream)
1.buffer:是一个指向用于保存数据的内存位置的指针
(是一个指针,对于fwrite来说,是要获取数据的地址)
2.size: 是每次读取的字节数
3.count: 是读取的次数
4.stream: 是数据写入的流(目标指针的文件)
- struct S s = {20, 90.5, "张三"};
- FILE* pf = fopen("test2.txt", "wb");
- if(pf != NULL){
- fwrite(&s, sizeof(struct S), 1, pf);//此时是二进制文件,看不懂
- fclose(pf);
- pf = NULL;
- }
-
- struct S tmp;
- FILE* pf = fopen("test2.txt", "rb");
- if(pf != NULL){
- fread(&tmp, sizeof(struct S), 1, pf);
- printf("%d %f %s", tmp.n, tmp.score, tmp.arr);
- fclose(pf);
- pf = NULL;
- }
int fseek ( FILE * stream, long int offset(偏移量), int origin );
其中origin是指指针的位置
宏:SEEK_CUR当前位置;SEEK_END文件末尾位置; SEEK_SET文件起始位置
- FILE* pf = fopen("test3.txt", "r"); char ch;
- if(pf != NULL)
- {
- //定位文件指针
- //fseek(pf, 2, SEEK_CUR);//当前默认指向第一个字符
- //fseek(pf, -2, SEEK_END);//SEEK_END是指向最后一个元素的后一位
- fseek(pf, 2, SEEK_SET);
- //读取文件
- ch = fgetc(pf);
- printf("%c\n", ch);
- fclose(pf);
- pf = NULL;
- }
- FILE* pf = fopen("test3.txt", "r"); char ch;
- if(pf != NULL)
- {
- //fseek(pf, 2, SEEK_SET);
- fgetc(pf);//fgetc之后指针就向后跳一位
- printf("%d\n",ftell(pf));
- fclose(pf);
- pf = NULL;
- }
void rewind(FILE * stream)
- FILE* pf = fopen("test3.txt", "r"); char ch;
- if(pf != NULL)
- {
- //fseek(pf, 2, SEEK_SET);
- fgetc(pf);//fgetc之后指针就向后跳一位
- printf("%d\n",ftell(pf));
- rewind(pf);
- printf("%d\n",ftell(pf));
- fclose(pf);
- pf = NULL;
- }
feof函数:用来判断文件结束的时候,是遇到文件尾结束,则返回真。
ferror函数:用来判定文件结束的时候,是读取遇到问题结束,则返回真;
- int c; // 注意:int,非char,要求处理EOF
- FILE* fp = fopen("test5.txt", "r");
- if(fp == NULL) {
- perror("File opening failed");
- return EXIT_FAILURE;}
-
- //fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
- while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
- {
- putchar(c);
- }
- printf("\n");
- //判断是什么原因结束的
- if (ferror(fp)) //ferror函数,文件读取结束后,是读取遇到问题后结束则返回真;
- puts("I/O error when reading");
- else if (feof(fp))//feof函数,文件读取结束时,是正常遇到文件尾读取结束则返回真;
- {
- puts("End of file reached successfully");
- printf("%d\n", feof(fp));
- }
-
- fclose(fp);
- fp = NULL;
补充:判断文件是否结束的方法有:
- FILE* pf = fopen("test4.txt", "r");
- int ch; // 注意:int,非char,要求处理EOF
- if(pf != NULL)
- {
- ch = fgetc(pf);
- printf("%d\n", ch);//文件里没有内容,打印-1
-
- fclose(pf);
- pf = NULL;
- }