14_文件
文件
文件概述
文件分类(存储介质)
磁盘文件: 文件的数据 存放在磁盘上 (音视频, 图片文件, 文档文件)
设备文件: 通过系统将外部设备抽象文件
文件分类(存储方式)
任何磁盘文件 物理上都是二进制存储
逻辑上: 磁盘文件分为二进制文件, 文本文件
文本文件: 基于字符编码的文件
二进制文件: 基于值编码的文件
文件缓冲区
目的: 提高访问效率 提高磁盘使用寿命
文件缓冲区的刷新方式
行刷新(遇到换行符 刷新)
//结果: 不会打印kjsdhfkksdjhnfkkdshn int main(int argc, char const *argv[]) { printf("kjsdhfkksdjhnfkkdshn"); while (1); return 0; } //结果: 会打印kjsdhfkksdjhnfkkdshn int main(int argc, char const *argv[]) { printf("kjsdhfkksdjhnfkkdshn\n"); while (1); return 0; }
满刷新(缓冲区数据放满刷新)
强制刷新(使用fflush 将缓存刷新)
fflush(stdout); //强制刷新
关闭刷新(关闭文件时, 将缓冲区数据 全部刷新)
模拟时钟
文件指针(重要)
所有操作文件的库函数 都需要借助文件指针 操作文件
在缓冲文件系统中,每个被使用的文件都要在内存中开辟一块FILE类型的区域,存放与操作文件相关的信息
文件的API
文件操作步骤: 打开 读写 关闭
打开文件fopen
FILE *fopen(const char *pathname, const char *mode);
pathname: 文件路径
mode: 打开文件方式
r w a + t b
r: 只读方式打开 w: 只写方式打开 a: 追加方式打开
+: 可读可写方式打开 t:文本文件方式打开(默认省略: r[t])
b: 二进制方式打开(必须显示: rb)
组合:
r/rb: 只读方式打开一个文本文件(不创建文件)
w/wb: 写方式打开文件(文件不存在,创建一个, 文件存在,就删除再创建)
r+/rb+: 可读可写方式打开文件(不创建新文件)
a/ab: 添加方式打开文件, 即在末尾添加内容, 当文件不存在时, 创建文件用于写
w+/wb+: 可读可写方式打开文件(文件不存在创建, 存在删除再创建)
a+/ab+: 和a/ab一样只不过可读可写
返回值:
成功: 打开的文件指针
失败: NULL
函数说明:
fopen函数打开一个已经存在的文件,并返回这个文件的文件指针(文件的标示)或者创建一个文件, 并打开此文件,然后返回文件的标示
关闭文件 fclose
int fclose(FILE *fp);
返回值:
成功返回 0
失败返回非0
一次读写一个字符
一次写一个字符
int fputc(int c, FILE *stream);
说明: fputc将c的值写到stream代表的文件中
返回值:
输出成功: 返回输出的字节值
输出失败: 返回EOF(定义再stdio.h中的符号常量, 值为-1)
一次读一个字符
int fgetc(FILE *stream);
说明: fgetc从stream的文件中读取一个字节, 并返回
返回值:
以t的方式: 读到文件结尾返回EOF
以b的方式: 读到文件结尾, 使用feof判断结尾
rewind(fp); //指针位置重置
int main(int argc, char const *argv[])
{
//写
FILE *fp = NULL;
fp = fopen("test.txt", "w+");
if (fp == NULL)
{
ferror("error: fopen\n");
}
else
{
char *file_data = "hello world";
while (*file_data != '\0')
{
fputc(*file_data, fp);
file_data++;
}
}
rewind(fp); //指针位置回到开头
//读
while (1)
{
char c = fgetc(fp);
if (c == EOF)
{
break;
}
printf("%c", c);
}
printf("\n");
fclose(fp);
return 0;
}
一次读写一个字符串
一次写一个字符串
int fputs(const char *s, FILE *stream);
一次读一个字符串
char *fgets(char *s, int size, FILE *stream);
说明: 从stream的文件中读取字符, 碰到换行符或末尾停止读取, 或者读取 size-1 个字节停止读取, 在读取的内容后面加一个'\0', 作为字符串的结尾
返回值:
成功返回目的字符串首地址, 即s
失败返回NULL
int main(int argc, char const *argv[])
{
FILE *fp = NULL;
char *text = "hhhh text \n sdklfjl\n dsjkfli\n oirffujgo\n idsjfuio\n isdhfuio\nsdf ";
fp = fopen("text.txt", "w+");
char c = fputs(text, fp);
if (c == EOF)
{
ferror("fputs error!");
}
rewind(fp);
FILE *fp2 = NULL;
fp2 = fopen("text2.txt", "w+");
while (1)
{
char buf[128] = "";
char *ret = fgets(buf, sizeof(buf), fp);
if (ret == NULL)
{
break;
}
fputs(buf, fp2);
}
fclose(fp);
fclose(fp2);
return 0;
}
一次读写n块数据
块写
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
解释:
ptr: 内存数据
size: 数据大小
nmemb: 数据数量
stream: 文件
说明: 将ptr写到stream
返回值: 实际写入的块数
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
返回值: 实际读到的块数, 不足一块 不计数
fread 读到的数据, 不便于查看
格式化读写
格式化读写
fprintf(文件指针, 格式字符串, 输出列表)
fscanf(文件指针, 格式字符串, 输出列表)
typedef struct s_hero
{
char name[16];
int atk;
int def;
} HERO;
int main(int argc, char const *argv[])
{
HERO hero[] = {{"德玛西亚", 50, 80}, {"小法", 70, 30}, {"亚索", 80, 30}};
FILE *fp = fopen("hero.txt", "w+");
int n = sizeof(hero)/sizeof(hero[0]);
for (int i = 0; i < n; i++)
{
fprintf(fp, "%s %d %d\n", hero[i].name, hero[i].atk, hero[i].def);
}
for (int i = 0; i < n; i++)
{
fscanf(fp, "%s %d %d", hero[i].name, hero[i].atk, hero[i].def);
}
for (int i = 0; i < n; i++)
{
printf("%s %d %d\n", hero[i].name, hero[i].atk, hero[i].def);
}
fclose(fp);
return 0;
}
文件的随机读写
文件默认是顺序读写: 读写才能移动流指针 用户不能修改
随机读写: 用户可以更改文件流指针的位置
引入案例
随机读写的API
fseek rewind ftell
rewind复位文件流指针
void rewind(FILE *stream);
ftell 返回文件流指针 距离文件首部的字节数
long ftell(FILE *stream);
fseek 文件流指针定位
int fseek(FILE *stream, long offset, int whence);
解析:
offset: 流指针的偏移量
正数: 向右偏移(单位为字节数)
负数: 向左偏移
whence: 起始位置
SEEK_SET 0: 文件开头
SEEK_CUR 1: 文件当前位置
SEEK_END 2: 文件末尾
一次性读取文件数据
int main(int argc, char const *argv[])
{
FILE *fp = fopen("c.txt", "r");
if (fp == NULL)
{
ferror("fopen error!");
return 0;
}
fseek(fp, 0, 2);
long len = ftell(fp);
printf("len = %ld\n", len);
rewind(fp);
unsigned char *text = (unsigned char *) calloc(1, len+1);
fread(text, len, 1, fp);
printf("%s\n", text);
printf("len = %d\n", strlen(text));
fclose(fp);
//释放堆区空间
if (text != NULL)
{
free(text);
text = NULL;
}
return 0;
}
文件加密器
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/**
* 文件加密
*/
int main(int argc, char const *argv[])
{
int order = 0;
char old_name[30] = "";
char new_name[30] = "";
unsigned int password = 0;
unsigned char *buf = NULL;
long len = 0;
FILE *ofp = NULL;
FILE *nfp = NULL;
while (1)
{
printf("********1:加密文件********\n");
printf("********2:解密文件********\n");
printf("********3:退出程序********\n");
printf("请输入指令: ");
scanf("%d", &order);
switch (order)
{
// 1 加密
case 1:
printf("请输入你的原文件名称(30个字符): ");
scanf("%s", old_name);
ofp = fopen(old_name, "r");
if (ofp == NULL)
{
printf("没找到该文件!\n");
break;
}
printf("请输入你的目的文件名称(30个字符): ");
scanf("%s", new_name);
nfp = fopen(new_name, "w");
if (nfp == NULL)
{
printf("nfp fopen error!\n");
break;
}
printf("please input your unsigned int passworld: ");
scanf("%u", &password);
fseek(ofp, 0, 2);
len = ftell(ofp);
rewind(ofp);
buf = (unsigned char *)calloc(1, len + 1);
fread(buf, len, 1, ofp);
// 加密
for (int i = 0; i < strlen(buf); i++)
{
buf[i] += password;
}
fwrite(buf, len, 1, nfp);
printf("save success!\n");
fclose(ofp);
fclose(nfp);
free(buf);
break;
// 解密
case 2:
printf("请输入你的原文件名称(30个字符): ");
scanf("%s", old_name);
ofp = fopen(old_name, "r");
if (ofp == NULL)
{
printf("没找到该文件!\n");
break;
}
printf("请输入你的目的文件名称(30个字符): ");
scanf("%s", new_name);
nfp = fopen(new_name, "w");
if (nfp == NULL)
{
printf("nfp fopen error!\n");
break;
}
printf("please input your unsigned int passworld: ");
scanf("%u", &password);
fseek(ofp, 0, 2);
len = ftell(ofp);
rewind(ofp);
buf = (unsigned char *)calloc(1, len + 1);
fread(buf, len, 1, ofp);
// 解密
for (int i = 0; i < strlen(buf); i++)
{
buf[i] -= password;
}
fwrite(buf, len, 1, nfp);
printf("save success!\n");
fclose(ofp);
fclose(nfp);
free(buf);
break;
case 3:
return 0;
default:
printf("命令错误,请重新输入!\n");
break;
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)