目录
- 1. 概述
- 2. 文件指针
- 3. 文件打开
- 4. 文件关闭
- 5. fputc的使用
- 6. fgetc和feof的使用
- 7. fputs和fgets使用
- 8. 格式化文件fprintf、fscanf
- 9. 文件块读写操作fread和fwrite
- 10. 文件的随机读取
- 11. 获取文件状态
- 12. 删除文件、重命名文件
- 总结
1. 概述
磁盘文件:指一组相关数据的有序集合,通常存储在外部介质(如磁盘)上,使用时才调入内存。
设备文件:把操作系统中把每一个与主机相连的输入、输出设备看作是一个文件,把它们的输入、输出等同于对磁盘文件的读和写。
计算机的存储在物理上是二进制的,以字节为单位进行顺序存储。
从用户或者操作系统使用的角度把文件分为:
- 文本文件:基于字符编码(ASCII、UNICODE等)的文件
- 二进制文件:基于值编码的文件
2. 文件指针
在c语言中用一个指针变量指向一个文件,这个指针称为文件指针。
- FILE *p
- 当我们使用C库函数fopen打开一个文件,它会返回一个指向该文件所有信息的指针。
3. 文件打开
fopen(const char *path, char *mode)
mode: 文件打开方式()
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>int main() {FILE* fp = NULL;fp = fopen("test.txt", "w");// 不存在会新建,存在就清空if (fp == NULL) {perror("fopen");return -1;}return 0;
}
4. 文件关闭
总是打开会消耗很多内存,要及时关闭。
int fclose(FILE* stream):返回0,表示失败;返回1,表示成功
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>int main() {FILE* fp = NULL;fp = fopen("test.txt", "w");// 不存在会新建,存在就清空if (fp == NULL) {perror("fopen");return -1;}fclose(fp);return 0;
}
5. fputc的使用
int fputc(int ch, FILE* fp):ch是写入的字符,会转换成unsigned char类型再写入;fp是文件指针
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>int main() {FILE* fp = NULL;fp = fopen("test.txt", "w");// 1. 字符char buf[] = "this is a file";int n = sizeof(buf) / sizeof(buf[0]);int ch;for (int i = 0; i < n; i++) {ch = fputc(buf[i], fp);printf("%c", buf[i]);}fclose(fp);return 0;
}
不过这里查看的话,是乱码
6. fgetc和feof的使用
int feof(FILE* stream):检测是否读取到了文件结尾。
int feof(FILE* stream):到文件结束,非0,没到为0
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>int main() {FILE* fp = NULL;fp = fopen("test.txt", "r");char ch;while (1) {ch = fgetc(fp);//if (ch == EOF) {// 判断文本文件结束符号。对二进制文件不能这么判断if(feof(fp) != 0){ // 可以判断文本文件和二进制的文件break;}putchar(ch);}fclose(fp);return 0;
}
输出结果:
this is a file
C:\Users\YUEXU\source\repos\CTest\x64\Debug\CTest.exe (进程 21136)已退出,代码为 0 (0x0)。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
7. fputs和fgets使用
int fputs(const char *str, FILE* stream):将str所指定的字符串写入stream指定的文件中,字符串结束符"\0"不写入文件
int fgets(char *str,int size, FILE* stream):从stream指定文件中读入字符,保存到str所指定的内存空间,知道出现换行字符、读到文件结尾或是已读了size - 1 个字符为止,最后自动会加上字符'\0'
作为字符串结尾
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main(){char* buf[] = {"hello world\n","haha\n"};int n = sizeof(buf) / sizeof(buf[0]);FILE* fp = NULL;fp = fopen("test.txt", "w");if (fp == NULL) {perror("fopen");return -1;}for (int i = 0; i < n; i++) {fputs(buf[i], fp);}fclose(fp);return 0;
}
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>int main() {char buf[100] = { 0 };FILE* fp = NULL;fp = fopen("test.txt", "r");if (fp == NULL) {perror("fopen");return -1;}while (feof(fp) == 0) {memset(buf, 0, sizeof(buf));fgets(buf, sizeof(buf), fp);printf("buf = %s\n", buf);}fclose(fp);return 0;
}
8. 格式化文件fprintf、fscanf
int fprintf(FILE* stream, const char* format, …):根据参数format字符串来转换并格式化数据,然后将结果输出到stream指定的文件中,指定出现字符串结束符'\0'
为止。
int fscanf(FILE* stream, const char* format, …):从stream指定的文件读取字符串,并根据参数format字符串来转换并格式化数据。
格式化写入文件:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>int main() {FILE* fp = NULL;fp = fopen("b.txt", "w");if (fp == NULL) {perror("fopen");return - 1;}fprintf(fp, "%d %d, %d", 10, 20, 30);fclose(fp);return 0;
}
格式化读取文件:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>int main() {FILE* fp = NULL;fp = fopen("b.txt", "r");if (fp == NULL) {perror("fopen");return -1;}int a, b, c;fscanf(fp, "%d %d, %d", &a, &b, &c);printf("%d %d, %d\n", a, b, c);fclose(fp);return 0;
}
输出结果:
10 20, 30C:\Users\YUEXU\source\repos\CTest\x64\Debug\CTest.exe (进程 27244)已退出,代码为 0 (0x0)。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
9. 文件块读写操作fread和fwrite
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE* stream):以数据块的方式给文件写入内容。
size_t fread(void *ptr, size_t size, size_t nmemb, FILE* stream):以数据块的方式给文件写入内容。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct stu {char name[30];int id;
}STU;int main() {STU s[3] = { 0 };for (int i = 0; i < 3;i++) {sprintf(s[i].name, "stu%d%d%d", i, i, i);s[i].id = i + 1;}FILE* fp = NULL;fp = fopen("b.txt", "w");if (fp == NULL) {perror("fopen");return -1;}// 1. 块操作写文件int ret;ret = fwrite(s, sizeof(STU), 3, fp);printf("ret = %d\n", ret);// 2. 块操作读文件STU s2[3];fread(s2, sizeof(STU), 3, fp);for (int i = 0; i < 3;i++) {printf("s:%s,%d\n", s[i].name, s[i].id);}fclose(fp);return 0;
}
运行结果:
ret = 3
s:stu000,1
s:stu111,2
s:stu222,3C:\Users\YUEXU\source\repos\CTest\x64\Debug\CTest.exe (进程 21964)已退出,代码为 0 (0x0)。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
10. 文件的随机读取
int fseek(FILE* stream, long offset, int whence):移动文件流(文件光标)的读写位置。offset是偏移量,whence的取值,SEEK_SET(从文件开头),SEEK_CUR(当前位置),SEEK_END(末尾)。
int ftell(FILE* stream):获取文件流(光标位置)的读取位置。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct stu {char name[30];int id;
}STU;int main() {FILE* fp = NULL;fp = fopen("b.txt", "r");if (fp == NULL) {perror("fopen");return -1;}int offset = ftell(fp);printf("文件当前偏移量:%d\n", offset);STU s3;fseek(fp, sizeof(STU) * 2, SEEK_SET);offset = ftell(fp);printf("文件当前偏移量:%d\n", offset);int ret = fread(&s3, sizeof(STU), 1, fp);if (ret == 1) {printf("第三个结构体:s:%s,%d\n", s3.name, s3.id);}offset = ftell(fp);printf("文件当前偏移量:%d\n", offset);return 0;
}
输出结果:
文件当前偏移量:0
文件当前偏移量:72
第三个结构体:s:stu222,3
文件当前偏移量:108C:\Users\YUEXU\source\repos\CTest\x64\Debug\CTest.exe (进程 4224)已退出,代码为 0 (0x0)。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
11. 获取文件状态
#include<sys/types.h>
#include<sys/stat.h>
int stat(const char *path, struct stat *buf):获取文件状态信息。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<sys/types.h>
int main(int argc, char* argv[]) {if (argc != 2) {printf("用法:xxx.exe 文件名\n");return -1;}struct stat s = { 0 };stat(argv[1], &s);printf("文件大小:%d\n", s.st_size);return 0;
}
在该文件的路径打开终端,cmd
输入命令:
gcc 该文件.c -o test
输入:
test.exe b.txt
输出结果:
文件大小:216
12. 删除文件、重命名文件
remove(文件名)
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>int main(int argc, char* argv[]) {if (argc != 2) {printf("用法:xxx.exe 需要删除文件名\n");return -1;}remove(argv[1]);return 0;
}
终端编译,
输入命令:
dir
输出结果:
驱动器 C 中的卷没有标签。卷的序列号是 C14D-581BC:\Users\YUEXU\source\repos\CTest 的目录2024/11/24 17:28 <DIR> .
2024/11/14 00:16 <DIR> ..
2024/11/24 17:02 216 b.txt
2024/11/14 00:25 <DIR> CTest
2024/11/15 00:05 1,312 CTest.aps
2024/11/14 00:27 868 CTest.cpp
2024/11/15 00:05 2,462 CTest.rc
2024/11/14 00:16 1,429 CTest.sln
2024/11/23 23:29 7,045 CTest.vcxproj
2024/11/23 23:29 1,852 CTest.vcxproj.filters
2024/11/16 01:28 389 CTest.vcxproj.user
2024/11/22 00:55 964 CTest1.c
2024/11/15 00:08 150 func.c
2024/11/14 23:22 50 func.h
2024/11/15 00:05 384 resource.h
2024/11/24 17:28 54,197 test.exe
2024/11/24 01:35 19 test.txt
2024/11/14 00:25 <DIR> x64
2024/11/24 17:27 3,758 文件操作.c
2024/11/23 23:27 2 文件操作.h
2024/11/23 23:26 4,181 结构体.c
2024/11/22 00:54 2 结构体.h18 个文件 79,280 字节4 个目录 51,060,375,552 可用字节
输入命令:
test.exe test.txt
dir
输出结果:
驱动器 C 中的卷没有标签。卷的序列号是 C14D-581BC:\Users\YUEXU\source\repos\CTest 的目录2024/11/24 17:28 <DIR> .
2024/11/14 00:16 <DIR> ..
2024/11/24 17:02 216 b.txt
2024/11/14 00:25 <DIR> CTest
2024/11/15 00:05 1,312 CTest.aps
2024/11/14 00:27 868 CTest.cpp
2024/11/15 00:05 2,462 CTest.rc
2024/11/14 00:16 1,429 CTest.sln
2024/11/23 23:29 7,045 CTest.vcxproj
2024/11/23 23:29 1,852 CTest.vcxproj.filters
2024/11/16 01:28 389 CTest.vcxproj.user
2024/11/22 00:55 964 CTest1.c
2024/11/15 00:08 150 func.c
2024/11/14 23:22 50 func.h
2024/11/15 00:05 384 resource.h
2024/11/24 17:28 54,197 test.exe
2024/11/14 00:25 <DIR> x64
2024/11/24 17:27 3,758 文件操作.c
2024/11/23 23:27 2 文件操作.h
2024/11/23 23:26 4,181 结构体.c
2024/11/22 00:54 2 结构体.h17 个文件 79,261 字节4 个目录 51,060,224,000 可用字节
很明显,test.txt删除了
重命名:rename(文件名,文件名)
总结
这块是基本操作,没有很难很深的东西,so easy!!!