入门
- 1. 流程控制基本概念
- 2. 流程控制 选择结构
- 3. 流程控制 循环结构
- 4. 四大跳转
- 5. 循环的嵌套
- 6. C 语言图形打印练习
- 7. 函数那点事
- 8. main 函数分析
- 9. 递归函数
- 10. 进制基本概念
- 11. 进制转换
- 12. 原码反码补码
- 13. 位运算符
- 14. 变量内存分析
- 15. Char 类型内存存储细节
- 16. 类型说明符详解
- 17. 数组那点事
- 18. 数组内部存储细节
- 19. 数组注意事项
- 20. 数组和函数
基础
- 1. 计算机常识
- 2. 什么是计算机程序
- 3. 什么是计算机语言
- 4. 常见的计算机语言类型有哪些
- 5. 什么是C语言
- 6. C语言发展历史
- 7. C语言标准
- 8. C语言现状
- 9. 为什么要学习C语言
- 10. 如何学好C语言
- 11. 编写C语言程序用什么工具
- 12. 什么是 QtCreator
- 13. 什么是环境变量
- 14. 如何创建C语言程序
- 15. C语言程序组成
- 16. 函数定义格式
- 17. 如何运行编写好的程序
- 18. C语言程序练习
- 19. 初学者如何避免程序出现 BUG
- 20. 多语言对比
- 21. 注释就是这么简单
- 22. 什么是关键字
- 23. 什么是标识符
- 24. 什么是数据
- 25. C语言数据类型
- 26. 什么是常量
- 27. C语言变量那点事
- 28. printf 函数
- 29. Scanf 函数
- 30. putchar 和 getchar
- 31. C语言运算符大全解
- 32. 阶段练习
进阶
- 1. 计数排序
- 2. 选择排序
- 3. 冒泡排序
- 4. 插入排序
- 5. 希尔排序
- 6. 折半查找
- 8. 二维数组那点事
- 9. 二维数组的遍历和存储
- 10. 二维数组与函数
- 11. 二维数组练习
- 12. 字符串的基本概念
- 13. 字符串常用方法
- 14. 字符串练习
- 15. 指针的基本概念
- 16. 指针变量那点事
- 17. 访问指针所指向的存储空间
- 18. 指针类型与二级指针
- 19. 数组指针的概念及定义
- 20. 指针与字符串
- 21. 指向函数指针
- 22. 结构体详解
- 23. 结构体数组
- 24. 结构体指针
- 25. 结构体内存分析
- 26. 结构体变量占用存储空间大小
- 27. 结构体嵌套定义
- 28. 共用体
- 29. 枚举
- 30. 全局变量和局部变量
- 31. 关键字
- 32. static 与 extern 对函数的作用
- 33. QtCreator 编译过程做了什么
- 34. 计算机运算过程分析
- 35. 预处理指令与宏定义
- 36. 条件编译
- 37. typedef 关键字
- 38. 宏定义与函数以及 typedef 区别
- 39. const 关键字
- 40. 内存管理
- 41. malloc 函数
- 42. free 函数
- 43. calloc 函数
- 44. realloc 函数
- 45. 链表与静态链表
- 46. 动态链表
- 47. 链表销毁与长度计算
- 48. 链表查找与删除
- 49. 文件基本概念
- 50. 文件的打开与关闭
- 51. 读写结构体
- 52. 文件操作函数
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
50. 文件的打开与关闭
文件的打开和关闭
FILE 结构体
FILE 结构体是对缓冲区和文件读写状态的记录者,所有对文件的操作,都是通过FILE 结构体完成的。
struct _iobuf {
char *_ptr; //文件输入的下一个位置
int _cnt; //当前缓冲区的相对位置
char *_base; //文件的起始位置)
int _flag; //文件标志
int _file; //文件的有效性验证
int _charbuf; //检查缓冲区状况,如果无缓冲区则不读取
int _bufsiz; // 缓冲区大小
char *_tmpfname; //临时文件名
};
typedef struct _iobuf FILE;
- fileopen函数
函数声明 | FILE fopen ( const char filename, const char * mode ); |
---|---|
所在文件 | stdio.h |
函数功能 | 以 mode 的方式,打开一个 filename 命名的文件,返回一个指向该文件缓冲的 FILE 结构体指针。 |
|参数及返回解析 |参数| charfilaname :要打开,或是创建文件的路径。| |参数| charmode :打开文件的方式。| |返回值| FILE* 返回指向文件缓冲区的指针,该指针是后序操作文件的句柄。|
mode | 处理方式 | 当文件不存在时 | 当文件存在时 | 向文件输入 | 从文件输出 |
---|---|---|---|---|---|
r | 读取 | 出错 | 打开文件 | 不能 | 可以 |
w | 写入 | 建立新文件 | 覆盖原有文件 | 可以 | 不能 |
a | 追加 | 建立新文件 | 在原有文件后追加 | 可以 | 不能 |
r+ | 读取/写入 | 出错 | 打开文件 | 可以 | 可以 |
w+ | 写入/读取 | 建立新文件 | 覆盖原有文件 | 可以 | 可以 |
a+ | 读取/追加 | 建立新文件 | 在原有文件后追加 | 可以 | 可以 |
注意点:
- Windows如果读写的是二进制文件,则还要加 b,比如 rb, r+b 等。 unix/linux 不区分文本和二进制文件
- fclose函数
函数声明 | int fclose ( FILE * stream ); |
---|---|
所在文件 | stdio.h |
函数功能 | fclose()用来关闭先前 fopen()打开的文件. |
函数功能 | 此动作会让缓冲区内的数据写入文件中, 并释放系统所提供的文件资源 |
参数及返回解析 | |
参数 | FILE* stream :指向文件缓冲的指针。 |
返回值 | int 成功返回 0 ,失败返回 EOF(-1)。 |
#include <stdio.h>
int main()
{
FILE *fp = fopen("test.txt", "w+");
fclose(fp);
return 0;
}
--
一次读写一个字符
- 写入
函数声明 | int fputc (int ch, FILE * stream ); |
---|---|
所在文件 | stdio.h |
函数功能 | 将 ch 字符,写入文件。 |
参数及返回解析 | |
参数 | FILE* stream :指向文件缓冲的指针。 |
参数 | int : 需要写入的字符。 |
返回值 | int 写入成功,返回写入成功字符,如果失败,返回 EOF。 |
#include <stdio.h>
int main()
{
// 1.打开一个文件
FILE *fp = fopen("test.txt", "w+");
// 2.往文件中写入内容
for(char ch = 'a'; ch <= 'z'; ch++){
// 一次写入一个字符
char res = fputc(ch, fp);
printf("res = %c\n", res);
}
// 3.关闭打开的文件
fclose(fp);
return 0;
}
- 读取
函数声明 | int fgetc ( FILE * stream ); |
---|---|
所在文件 | stdio.h |
函数功能 | 从文件流中读取一个字符并返回。 |
参数及返回解析 | |
参数 | FILE* stream :指向文件缓冲的指针。 |
返回值 | int 正常,返回读取的字符;读到文件尾或出错时,为 EOF。 |
#include <stdio.h>
int main()
{
// 1.打开一个文件
FILE *fp = fopen("test.txt", "r+");
// 2.从文件中读取内容
char res = EOF;
while((res = fgetc(fp)) != EOF){
printf("res = %c\n", res);
}
// 3.关闭打开的文件
fclose(fp);
return 0;
}
- 判断文件末尾
- feof函数
函数声明 | int feof( FILE * stream ); |
---|---|
所在文件 | stdio.h |
函数功能 | 判断文件是否读到文件结尾 |
参数及返回解析 | |
参数 | FILE* stream :指向文件缓冲的指针。 |
返回值 | int 0 未读到文件结尾,非零 读到文件结尾。 |
#include <stdio.h>
int main()
{
// 1.打开一个文件
FILE *fp = fopen("test.txt", "r+");
// 2.从文件中读取内容
char res = EOF;
// 注意: 由于只有先读了才会修改标志位,
// 所以通过feof判断是否到达文件末尾, 一定要先读再判断, 不能先判断再读
while((res = fgetc(fp)) && (!feof(fp))){
printf("res = %c\n", res);
}
// 3.关闭打开的文件
fclose(fp);
return 0;
}
- 注意点:
- feof 这个函数,是去读标志位判断文件是否结束的。
- 而标志位只有读完了才会被修改, 所以如果先判断再读标志位会出现多打一次的的现象
- 所以企业开发中使用feof函数一定要先读后判断, 而不能先判断后读
作业
实现文件的简单加密和解密
#include <stdio.h>
#include <string.h>
void encode(char *name, char *newName, int code);
void decode(char *name, char *newName, int code);
int main()
{
encode("main.c", "encode.c", 666);
decode("encode.c", "decode.c", 666);
return 0;
}
/**
* @brief encode 加密文件
* @param name 需要加密的文件名称
* @param newName 加密之后的文件名称
* @param code 秘钥
*/
void encode(char *name, char *newName, int code){
FILE *fw = fopen(newName, "w+");
FILE *fr = fopen(name, "r+");
char ch = EOF;
while((ch = fgetc(fr)) && (!feof(fr))){
fputc(ch ^ code, fw);
}
fclose(fw);
fclose(fr);
}
/**
* @brief encode 解密文件
* @param name 需要解密的文件名称
* @param newName 解密之后的文件名称
* @param code 秘钥
*/
void decode(char *name, char *newName, int code){
FILE *fw = fopen(newName, "w+");
FILE *fr = fopen(name, "r+");
char ch = EOF;
while((ch = fgetc(fr)) && (!feof(fr))){
fputc(ch ^ code, fw);
}
fclose(fw);
fclose(fr);
}
一次读写一行字符
什么是行
行是文本编辑器中的概念,文件流中就是一个字符。这个在不同的平台是有差异的。window 平台 '\r\n',linux 平台是'\n'
平台差异
windows 平台在写入'\n'是会体现为'\r\n',linux 平台在写入'\n'时会体现为'\n'。windows 平台在读入'\r\n'时,体现为一个字符'\n',linux 平台在读入'\n'时,体现为一个字符'\n'
- linux 读 windows 中的换行,则会多读一个字符,windows 读 linux 中的换行,则没有问题
#include <stdio.h>
int main()
{
FILE *fw = fopen("test.txt", "w+");
fputc('a', fw);
fputc('\n', fw);
fputc('b', fw);
fclose(fw);
return 0;
}
- 写入一行
函数声明 | int fputs(char str,FILE fp) |
---|---|
所在文件 | stdio.h |
函数功能 | 把 str 指向的字符串写入 fp 指向的文件中。 |
参数及返回解析 | |
参数 | char * str : 表示指向的字符串的指针。 |
参数 | FILE *fp : 指向文件流结构的指针。 |
返回值 | int 正常,返 0;出错返 EOF。 |
#include <stdio.h>
int main()
{
FILE *fw = fopen("test.txt", "w+");
// 注意: fputs不会自动添加\n
fputs("lnj\n", fw);
fputs("it666\n", fw);
fclose(fw);
return 0;
}
- 遇到\0自动终止写入
#include <stdio.h>
int main()
{
FILE *fp = fopen("test.txt", "w+");
// 注意: fputs写入时遇到\0就会自动终止写入
fputs("lnj\0it666\n", fp);
fclose(fp);
return 0;
}
- 读取一行
函数声明 | char fgets(char str,int length,FILE *fp) |
---|---|
所在文件 | stdio.h |
函数功能 | 从 fp 所指向的文件中,至多读 length-1 个字符,送入字符数组 str 中, 如果在读入 length-1 个字符结束前遇\n 或 EOF,读入即结束,字符串读入后在最后加一个‘\0’字符。 |
参数及返回解析 | |
参数 | char * str :指向需要读入数据的缓冲区。 |
参数 | int length :每一次读数字符的字数。 |
参数 | FILE* fp :文件流指针。 |
返回值 | char * 正常,返 str 指针;出错或遇到文件结尾 返空指针 NULL。 |
- 最多只能读取N-1个字符
#include <stdio.h>
int main()
{
FILE *fp = fopen("test.txt", "w+");
// 注意: fputs不会自动添加\n
fputs("it666\n", fp);
// 将FILE结构体中的读写指针重新移动到最前面
// 注意: FILE结构体中读写指针每读或写一个字符后都会往后移动
rewind(fp);
char str[1024];
// 从fp中读取4个字符, 存入到str中
// 最多只能读取N-1个字符, 会在最后自动添加\0
fgets(str, 4, fp);
printf("str = %s", str); // it6
fclose(fp);
return 0;
}
- 遇到\n自动结束
#include <stdio.h>
int main()
{
FILE *fp = fopen("test.txt", "w+");
// 注意: fputs不会自动添加\n
fputs("lnj\n", fp);
fputs("it666\n", fp);
// 将FILE结构体中的读写指针重新移动到最前面
// 注意: FILE结构体中读写指针每读或写一个字符后都会往后移动
rewind(fp);
char str[1024];
// 从fp中读取1024个字符, 存入到str中
// 但是读到第4个就是\n了, 函数会自动停止读取
// 注意点: \n会被读取进来
fgets(str, 1024, fp);
printf("str = %s", str); // lnj
fclose(fp);
return 0;
}
- 读取到EOF自动结束
#include <stdio.h>
int main()
{
FILE *fp = fopen("test.txt", "w+");
// 注意: fputs不会自动添加\n
fputs("lnj\n", fp);
fputs("it666", fp);
// 将FILE结构体中的读写指针重新移动到最前面
// 注意: FILE结构体中读写指针每读或写一个字符后都会往后移动
rewind(fp);
char str[1024];
// 每次从fp中读取1024个字符, 存入到str中
// 读取到文件末尾自动结束
while(fgets(str, 1024, fp)){
printf("str = %s", str);
}
fclose(fp);
return 0;
}
- 注意点:
- 企业开发中能不用feof函数就不用feof函数
- 如果最后一行,没有行‘\n’的话则少读一行
#include <stdio.h>
int main()
{
FILE *fp = fopen("test.txt", "w+");
// 注意: fputs不会自动添加\n
fputs("12345678910\n", fp);
fputs("12345678910\n", fp);
fputs("12345678910", fp);
// 将FILE结构体中的读写指针重新移动到最前面
// 注意: FILE结构体中读写指针每读或写一个字符后都会往后移动
rewind(fp);
char str[1024];
// 每次从fp中读取1024个字符, 存入到str中
// 读取到文件末尾自动结束
while(fgets(str, 1024, fp) && !feof(fp)){
printf("str = %s", str);
}
fclose(fp);
return 0;
}
- 作业:
- 利用fgets(str, 5, fp)读取下列文本会读取多少次?
12345678910
12345
123
一次读写一块数据
- C 语言己经从接口的层面区分了,文本的读写方式和二进制的读写方式。前面我们讲的是文本的读写方式。
所有的文件接口函数,要么以 '\0',表示输入结束,要么以 '\n', EOF(0xFF)表示读取结束。 '\0' '\n' 等都是文本文件的重要标识,而所有的二进制接口对于这些标识,是不敏感的。 +二进制的接口可以读文本,而文本的接口不可以读二进制
一次写入一块数据
函数声明 | int fwrite(void buffer, int num_bytes, int count, FILE fp) |
---|---|
所在文件 | stdio.h |
函数功能 | 把buffer 指向的数据写入fp 指向的文件中 |
参数 | char * buffer : 指向要写入数据存储区的首地址的指针 |
int num_bytes: 每个要写的字段的字节数count | |
int count : 要写的字段的个数 | |
FILE* fp : 要写的文件指针 | |
返回值 | int 成功,返回写的字段数;出错或文件结束,返回 0。 |
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fp = fopen("test.txt", "wb+");
// 注意: fwrite不会关心写入数据的格式
char *str = "lnj\0it666";
/*
* 第一个参数: 被写入数据指针
* 第二个参数: 每次写入多少个字节
* 第三个参数: 需要写入多少次
* 第四个参数: 已打开文件结构体指针
*/
fwrite((void *)str, 9, 1, fp);
fclose(fp);
return 0;
}
- 一次读取一块数据
函数声明 | int fread(void buffer, int num_bytes, int count, FILE fp) |
---|---|
所在文件 | stdio.h |
函数功能 | 把fp 指向的文件中的数据读到 buffer 中。 |
参数 | char * buffer : 指向要读入数据存储区的首地址的指针 |
int num_bytes: 每个要读的字段的字节数count | |
int count : 要读的字段的个数 | |
FILE* fp : 要读的文件指针 | |
返回值 | int 成功,返回读的字段数;出错或文件结束,返回 0。 |
#include <stdio.h>
int main()
{
// test.txt中存放的是"lnj\0it666"
FILE *fr = fopen("test.txt", "rb+");
char buf[1024] = {0};
// fread函数读取成功返回读取到的字节数, 读取失败返回0
/*
* 第一个参数: 存储读取到数据的容器
* 第二个参数: 每次读取多少个字节
* 第三个参数: 需要读取多少次
* 第四个参数: 已打开文件结构体指针
*/
int n = fread(buf, 1, 1024, fr);
printf("%i\n", n);
for(int i = 0; i < n; i++){
printf("%c", buf[i]);
}
fclose(fr);
return 0;
}
- 注意点:
- 读取时num_bytes应该填写读取数据类型的最小单位, 而count可以随意写
- 如果读取时num_bytes不是读取数据类型最小单位, 会引发读取失败
- 例如: 存储的是char类型 6C 6E 6A 00 69 74 36 36 36 如果num_bytes等于1, count等于1024, 那么依次取出 6C 6E 6A 00 69 74 36 36 36 , 直到取不到为止 如果num_bytes等于4, count等于1024, 那么依次取出[6C 6E 6A 00][69 74 36 36] , 但是最后还剩下一个36, 但又不满足4个字节, 那么最后一个36则取不到
#include <stdio.h>
#include <string.h>
int main()
{
// test.txt中存放的是"lnj\0it666"
FILE *fr = fopen("test.txt", "rb+");
char buf[1024] = {0};
/*
while(fread(buf, 4, 1, fr) > 0){
printf("%c\n", buf[0]);
printf("%c\n", buf[1]);
printf("%c\n", buf[2]);
printf("%c\n", buf[3]);
}
*/
/*
while(fread(buf, 1, 4, fr) > 0){
printf("%c\n", buf[0]);
printf("%c\n", buf[1]);
printf("%c\n", buf[2]);
printf("%c\n", buf[3]);
}
*/
while(fread(buf, 1, 1, fr) > 0){
printf("%c\n", buf[0]);
}
fclose(fr);
return 0;
}
- 注意: fwrite和fread本质是用来操作二进制的
- 所以下面用法才是它们的正确打开姿势
#include <stdio.h>
int main()
{
FILE *fp = fopen("test.txt", "wb+");
int ages[4] = {1, 3, 5, 6};
fwrite(ages, sizeof(ages), 1, fp);
rewind(fp);
int data;
while(fread(&data, sizeof(int), 1, fp) > 0){
printf("data = %i\n", data);
}
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论