文件操作(文件指针+顺序/随机读写)
目录
- 一、文件
- 1、以文件功能分类:
- 2、文件名
- 二、文件指针
- 三、文件的打开和关闭
- 1、fopen fclose
- 2、"r" - 读
- 3、"w" - 写
- 四、顺序读写
- 1、有哪些函数
- 2、fputc - 字符输出(写)
- 2.1、所有输出流
- 3、fgetc - 字符输入(读)
- 3.1、从文件里读
- 3.2、从标准输入读
- 4、对比putchar printf getchar scanf
- 5、fputs - 文本输出(写)
- 6、fgets - 文本输入(读)
- 使用示例:
- 7、fprintf - 格式化输出
- 8、fscanf - 格式化输入
- 9、fwrite - 二进制输出
- 10、fread - 二进制输入
- 11、对比一组函数
- sscanf 与 sprintf
- 优化通讯录程序
- 五、文件的随机读写
- 1、fseek
- 2、ftell
- 3、rewind
- 六、文本文件和二进制文件
- 七、文件结束判定
- feof
- 八、文件缓冲区
一、文件
什么是文件:
磁盘上的文件就是文件
1、以文件功能分类:
程序文件:
源程序文件test.c 目标文件test.obj 可执行程序test.exe
数据文件:
文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要 从中读取数据的文件,或者输出内容的文件,如:data.txt
2、文件名
一个文件要有一个唯一的文件标识,以便用户识别和引用。
文件名包含3部分:文件路径+文件名主干+文件后缀
例如: c:\code\test.txt
为了方便起见,文件标识常被称为文件名。
二、文件指针
每一个打开的文件都会后一个与它匹配的文件信息区,存储文件信息
这些信息保存在一个结构体变量中,如:struct FILE f;。该结构体类型是有系统声明的,取名FILE.
例如,VS2008编译环境提供的 stdio.h 头文件中有以下的文件类型声明:
struct _iobuf {char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
};
typedef struct _iobuf FILE;
每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,使用者不必关心细节。
一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。
三、文件的打开和关闭
1、fopen fclose
ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件。
2、“r” - 读
#include <stdio.h>int main()
{FILE* pf = fopen("data.txt", "r");if (pf == NULL){perror("fopen"); // 输出:// fopen: No such file or directory// 因为文件不存在return -1;}// 读文件// 关闭文件fclose(pf);pf = NULL;return 0;
}
绝对路径
#include <stdio.h>int main()
{FILE* pf = fopen("C:\\Users\\Chloe\\Desktop\\data.txt", "r"); // 绝对路径// FILE* pf = fopen("data.txt", "r"); // 相对路径if (pf == NULL){perror("fopen");return -1;}// 读文件// 关闭文件fclose(pf);pf = NULL;return 0;
}
3、“w” - 写
#include <stdio.h>int main()
{FILE* pf = fopen("C:\\Users\\Chloe\\Desktop\\data.txt", "w"); // 会生成一个文件if (pf == NULL){perror("fopen");return -1;}// 读文件// 关闭文件fclose(pf);pf = NULL;return 0;
}
四、顺序读写
1、有哪些函数
fputc - 字符输出函数 写一个字符
fgetc - 字符输入函数 读一个字符
2、fputc - 字符输出(写)
int fgetc( FILE *stream );
#include <stdio.h>int main()
{FILE* pf = fopen ("C:\\Users\\Chloe\\Desktop\\data.txt", "w");if (NULL == pf){perror("fopen");return -1;}// 写文件fputc('b', pf); // 在data.txt中写入bitfputc('i', pf);fputc('t', pf);// 关闭文件fclose(pf);pf = NULL;return 0;
}
2.1、所有输出流
流:高度抽象的概念
C语言的程序,只要运行起来,就默认打开了三个流:stdout - 标准输出流stdin - 标准输入流stderr - 标准错误流类型都是 FILE*
#include <stdio.h>int main()
{fputc('b', stdout);fputc('i', stdout);fputc('t', stdout);
}
3、fgetc - 字符输入(读)
int fputc( int c, FILE *stream );
3.1、从文件里读
把文件内容改成abcdef 会输出什么?
#include <stdio.h>int main()
{FILE* pf = fopen ("C:\\Users\\Chloe\\Desktop\\data.txt", "r");if (NULL == pf){perror("fopen");return -1;}// 读文件int ch = fgetc(pf); printf("%c\n", ch); // ach = fgetc(pf);printf("%c\n", ch); // bch = fgetc(pf);printf("%c\n", ch); // c// 关闭文件fclose(pf);pf = NULL;return 0;
}
3.2、从标准输入读
也可以从标准输入读,也就是键盘
#include <stdio.h>int main()
{int ch = fgetc(stdin);printf("%c\n", ch);ch = fgetc(stdin);printf("%c\n", ch);ch = fgetc(stdin);printf("%c\n", ch);}
4、对比putchar printf getchar scanf
#include <stdio.h>int main()
{fputc('b', stdout);// putchar printf("%c", ch);int ch = fgetc(stdin);// getchar scanf("%c", ch);printf("%c\n", ch);
}
5、fputs - 文本输出(写)
int fputs( const char *string, FILE *stream );
把数据放进流里
#include <stdio.h>int main()
{FILE* pf = fopen("data.txt", "w");if (NULL == pf){perror("fopen");return -1;}// 写文件// 写一行数据fputs("hello world\n", pf);fputs("hello bit\n", pf);fclose(pf);pf = NULL;
}
6、fgets - 文本输入(读)
char *fgets( char *string, int n, FILE *stream );
从流里读数据
使用示例:
想要读5个字符,但实际只读了4个字符,因为后面后有一个 \0
改成20:
7、fprintf - 格式化输出
int fprintf( FILE *stream, const char *format [, argument ]...);
与 printf 函数对比
示例:
#include <stdio.h>struct S
{int n;double d;
};int main()
{struct S s = { 100, 3.14 };FILE* pf = fopen("data.txt", "w");if (NULL == pf){perror("fopen");return -1;}// 写文件fprintf(pf, "%d %lf", s.n, s.d);// 关闭文件fclose(pf);pf = NULL;return 0;
}
8、fscanf - 格式化输入
int fscanf( FILE *stream, const char *format [, argument ]... );
与 printf 函数对比
示例:
#include <stdio.h>struct S
{int n;double d;
};int main()
{struct S s = { 0 };FILE* pf = fopen("data.txt", "r");if (NULL == pf){perror("fopen");return -1;}// 读文件fscanf(pf, "%d %lf", &(s.n), &(s.d));printf("%d %lf", s.n, s.d);// 关闭文件fclose(pf);pf = NULL;return 0;
}
9、fwrite - 二进制输出
示例:
wb”(只写) 为了输出数据,打开一个二进制文件
#include <stdio.h>struct S
{int n;double d;char name[10];
};int main()
{struct S s = { 100, 3.24, "zhangsan"};FILE* pf = fopen("data.txt", "wb");if (NULL == pf){perror("fopen");return -1;}// 以二进制方式写fwrite(&s, sizeof(s), 1, pf);// 关闭文件fclose(pf);pf = NULL;return 0;
}
文件内输出一堆二进制
10、fread - 二进制输入
示例:
#include <stdio.h>struct S
{int n;double d;char name[10];
};int main()
{struct S s = { 100, 3.24, "zhangsan" };FILE* pf = fopen("data.txt", "rb");if (NULL == pf){perror("fopen");return -1;}// 读文件 - 以二进制方式读fwrite(&s, sizeof(s), 1, pf);// 打印文件printf("%d %lf %s\n", s.n, s.d, s.name); // 100 3.240000 zhangsan// 关闭文件fclose(pf);pf = NULL;return 0;
}
11、对比一组函数
scanf/fscanf/sscanf
printf/fprintf/sprintf
scanf:从标准输入流(键盘)读取格式化的数据
printf:把格式化的数据输出到标准输出(屏幕)上
fscanf:从所有的输入流读取格式化的数据
fprintf:把格式化的数据输出到所有输出流(屏幕 / 文件)上
剩下 sscanf 和 sprintf 是什么意思?
sscanf 与 sprintf
从一个字符串里读格式化的数据
写格式化的数据到字符串里
举例:
#include <stdio.h>struct S
{int n;double d;char name[10];
};int main()
{char arr[100] = { 0 };struct S s = { 100, 3.14, "zhangsan" };// 把一个格式化的数据转换成字符串sprintf(arr, "%d %lf %s\n", s.n, s.d, s.name);// 打印printf("%s\n", arr);return 0;
}
- 输出:
- 100 3.140000 zhangsan
- 由此可见 sprintf 的作用是:
- 把格式化的数据转换成对应的字符串
如何从arr里解析出格式化的结构体放进tmp:
#include <stdio.h>struct S
{int n;double d;char name[10];
};int main()
{char arr[100] = { 0 };struct S s = { 100, 3.14, "zhangsan" };struct S tmp = { 0 };// 把一个格式化的数据转换成字符串sprintf(arr, "%d %lf %s\n", s.n, s.d, s.name);// 以字符串形式打印printf("%s\n", arr); // 100 3.140000 zhangsan// 从arr中的字符串中提取一个格式化的数据sscanf(arr, "%d %lf %s", &(tmp.n), &(tmp.d), tmp.name);// 按照格式化的形式打印的printf("%d %lf %s\n", tmp.n, tmp.d, tmp.name); // 100 3.140000 zhangsanreturn 0;
}
- 由此可见 sscanf 的作用是:
- 从字符串中读取一个格式化的数据(把一个字符串转换成一个格式化的数据)
优化通讯录程序
文件的版本:
【Contact】结构体+动态内存管理+文件存储实现简易通讯录代码
五、文件的随机读写
1、fseek
int fseek ( FILE * stream, long int offset, int origin );
根据文件指针的位置和偏移量来定位文件指针
#include <stdio.h>int main()
{FILE* pf = fopen("data.txt", "r");if (NULL == pf){perror("fopen");return -1;}// 读文件 随机读写// 1、读a//int ch = fgetc(pf);//printf("%c\n", ch); // a// 2、如果第一次就要读取'c'fseek(pf, 2, SEEK_SET); // 从起始位置偏移2指向cint ch = fgetc(pf);printf("%c\n", ch); // c// 3、读'b'// 读完c 指向d 要读取b需要从当前位置开始偏移-2fseek(pf, -2, SEEK_CUR);ch = fgetc(pf);printf("%c\n", ch); // bfclose(pf);pf = NULL;return 0;
}
2、ftell
long int ftell ( FILE * stream );
返回文件指针相对于起始位置的偏移量
计算文件指针相较于起始位置的偏移量:
#include <stdio.h>int main()
{FILE* pf = fopen("data.txt", "r");if (NULL == pf){perror("fopen");return -1;}// 读取'c'fseek(pf, 2, SEEK_SET);int ch = fgetc(pf);printf("%c\n", ch);// 读'b'fseek(pf, -2, SEEK_CUR);ch = fgetc(pf);printf("%c\n", ch);// 计算偏移量// 读取b后指向c 偏移量较起始位置为2int ret = ftell(pf);printf("%d\n", ret); // 2fclose(pf);pf = NULL;return 0;
}
3、rewind
void rewind ( FILE * stream );
让文件指针的位置回到文件的起始位置
#include <stdio.h>int main()
{FILE* pf = fopen("data.txt", "r");if (NULL == pf){perror("fopen");return -1;}// 读取'c'fseek(pf, 2, SEEK_SET);int ch = fgetc(pf);printf("%c\n", ch);// 读'b'fseek(pf, -2, SEEK_CUR);ch = fgetc(pf);printf("%c\n", ch);// 计算偏移量int ret = ftell(pf);printf("%d\n", ret); // 2// 让指针回到起始位置// 再次从起始位置打印 还是arewind(pf);ch = fgetc(pf);printf("%c\n", ch); // afclose(pf);pf = NULL;return 0;
}
六、文本文件和二进制文件
十进制10000的二进制存储:
ASCII形式 / 二进制形式
5字节 4字节
#include <stdio.h>int main()
{FILE* pf = fopen("data.txt", "wb");if (NULL == pf){perror("fopen");return -1;}// 以二进制形式写文件int a = 10000;fwrite(&a, 4, 1, pf);fclose(pf);pf = NULL;return 0;
}
七、文件结束判定
- 文本文件读取是否结束,判断返回值是否为EOF (fgetc),或者NULL(fgets)
例如:
fgetc判断是否为EOF.
fgets判断返回值是否为NULL. - 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。
例如:
fread判断返回值是否小于实际要读的个数。
字符输入函数fgetc返回int,遇到错误或文件结束返回EOF
如果用fgetc读取文件,可以判断fgetc的返回值是否是EOF,来判定文件是否读取结束
文本行输入函数fgets返回起始地址,遇到错误或文件结束返回NULL
#include <stdio.h>int main()
{FILE* pf = fopen("data.txt", "r");if (pf == NULL){perror("fopen");return -1;}int ch = 0;while ((ch = fgetc(pf)) != EOF){printf("%c ", ch);}fclose(pf);pf = NULL;return 0;
}
feof
feof不是用来判断文件是否读取结束的
文本文件的例子:
#include <stdio.h>
#include <stdlib.h>int main(void)
{int c; // 注意:int,非char,要求处理EOFFILE* fp = fopen("test.txt", "r");if (!fp) {perror("File opening failed");return EXIT_FAILURE;}//fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOFwhile ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环{putchar(c);}//判断是什么原因结束的if (ferror(fp))puts("I/O error when reading");else if (feof(fp))puts("End of file reached successfully");fclose(fp);fp = NULL;
}
二进制文件的例子:
#include <stdio.h>enum { SIZE = 5 };int main(void)
{double a[SIZE] = { 1.0,2.0,3.0,4.0,5.0 };double b = 0.0;size_t ret_code = 0;FILE* fp = fopen("test.bin", "wb"); // 必须用二进制模式fwrite(a, sizeof(*a), SIZE, fp); // 写 double 的数组fclose(fp);fp = fopen("test.bin", "rb");// 读 double 的数组while ((ret_code = fread(&b, sizeof(double), 1, fp)) >= 1){printf("%lf\n", b);}if (feof(fp))printf("Error reading test.bin: unexpected end of file\n");else if (ferror(fp)) {perror("Error reading test.bin");}fclose(fp);fp = NULL;
}
总结:
feof是当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束
ferror 用途:文件读取结束了,判断是不是遇到错误后读取结束
八、文件缓冲区
测试代码:
#include <stdio.h>
#include <windows.h>
//VS2013 WIN10环境测试int main()
{FILE* pf = fopen("test.txt", "w");fputs("abcdef", pf); // 先将代码放在缓冲区printf("睡眠10s 已经写数据了 打开test.txt文件 发现文件没有内容\n");Sleep(10000);printf("刷新缓冲区\n");fflush(pf); // 刷新缓冲区时 才将输出缓冲区的数据写到文件(磁盘)printf("再睡眠10s 此时 再次打开test.txt文件 文件有内容了\n");Sleep(10000);// 注:fclose关闭文件的时候 也会刷新缓冲区pf = NULL;return 0;
}
结论:
因为有缓冲区的存在,C语言在操作文件时,需要做刷新缓冲区或者在文件操作结束时关闭文件(fclose关闭文件的时候 也会刷新缓冲区),否则可能导致读写文件问题
文件操作(文件指针+顺序/随机读写)相关推荐
- AIR文件操作(三):使用FileStream对象读写文件
快速上手例: 例1.读xml var testXML:XML; var file:File = File.documentsDirectory.resolvePath("Mousebomb/ ...
- java流与文件——操作文件
[0]README 0.1) 本文描述转自 core java volume 2, 旨在理解 java流与文件--操作文件 的相关知识: 0.2) for source code, please vi ...
- Linux——权限|shell运行原理——外壳程序|Linux权限的概念|对人操作|角色和文件操作|文件类型访问权限|修改权限ugo+-|8进制|修改权限|更改文件的拥有
目录 shell运行原理--外壳程序 Linux权限的概念 对人操作 角色和文件操作 文件类型
- C语言基础14——文件操作。文本文件或二进制文件读写。通讯录的改造。文件缓冲区讲解
目录 为什么使用文件? 什么是文件? 文件的打开和关闭 文件指针 文件的打开和关闭 文件的打开方式 流 重定义文件 文件流 文件的顺序读写 以字符形式读写文本文件 fputc()函数 fgetc()函 ...
- Python基础day07 作业解析【文件操作(文件读写、文件夹操作)】
视频.源码.课件.软件.笔记:超全面Python基础入门教程[十天课程]博客笔记汇总表[黑马程序员] Python基础day07[文件读写.文件夹操作.面向对象(类.对象)] 目录 加强训练 题目1 ...
- VC 文件操作(文件查找,打开/保存,读/写,复制/删除/重命名)
右击项目->属性->字符集:使用多字节字符集. 这样可以使用char到CString的转化. char sRead[20] = ""; CString strtest ...
- python文件读取与输出_python基本文件操作(文件输入和输出)
文件输入输出中常用的文件对象方法: open: 返回一个新的文件对象,调用该对象的上的方法可对文件进行任何操作 readline: 读取一行数据包括结尾的换行符在内 write: 将数据写入文件中 c ...
- 【Delphi入门】文件系统(文件分类 文件文本变量 文件操作 文件流操作)
文件分类 文本文件(TextFile) & 二进制文件(Flie) 二进制形式存放数据占有存储空间较少,但不直观:文本文件与之相反 文件是由相同类型的数据元素组成的序列.在DELPHI中对文件 ...
- Linux学习笔记6 文件操作——文件描述符
基于文件描述符的文件操作 进程一启动,内核就打开了三个描述符,0(标准输入 STDIN),1(标准输出STDOUT), 2(标准错误输出STDERR).Linux用整形数做文件操作,因此称为文件描述符 ...
最新文章
- 7-19 支票面额 (C语言)
- plsql 参数中in out in的区别讲解
- 如何在PySide中使用qrc资源文件
- github网址无法访问怎么办?
- 我化身保姆为你提供 html 教学服务(6)
- 在VMware开启此虚拟机时出现内部错误
- 剑指Offer - 面试题66. 构建乘积数组(正反遍历)
- C++ 堆区和栈区的区别
- acm国际大学上计算机竞赛,ACM国际大学生程序设计竞赛
- Vista忘记密码如何登录?
- 库依赖关系和开源供应链带来的噩梦
- ./configure --prefix --with解释
- C语言常量定义#define和const区别解析
- 局域网IP扫描工具-OpUtils
- 清华大学模拟电子技术视频教程
- 10个资源满满的网站,偷偷收藏起来吧!
- visual studio 2015无法打开包括文件
- 网龙百万3D角色编辑系统介绍
- 从大数据的角度看 房价一定会下跌
- 重装系统(超详细教程)----大白菜教程