目录
5、文件块的读写fread fwrite 内存数据原样 输出到磁盘
6、文件块的格式化读写fprintf(写) fscanf(读)
知识点1【文件的概述】(了解)
磁盘文件:文件用来存放程序、文档、音频、视频数据、图片等数据的。
设备文件:在操作系统中把每一个与主机相连的输入、输出设备看作是一个文件,把它们的输入、输出等同于对磁盘文 件的读和写
将缓冲区数据 写入文件的方式:
1、满刷新:数据写满缓冲区时 数据才写入文件
2、行刷新:缓冲区数据 遇到换行符 将数据写入文件,printf("hellword\n");
3、强制刷新:fflush(stdout);
4、关闭刷新
案例
#include <stdio.h>
#include <unistd.h>
void test00(){
int time = 0;
while(1){
printf("\r\t\t\t\t\t%02d:%02d", time/60, time%60);
fflush(stdout);
sleep(1);
time++;
}
}
int main(int argc, char const *argv[])
{
test00();
return 0;
}
知识点2【磁盘文件分类】(了解)
磁盘文件 在物理上 都是二进制存储。
文本文件:基于字符编码的文件
二进制文件:基于值编码的文件 (内存数据原样 输出到磁盘)
文本文件:
基于字符编码,常见编码有 ASCII、UNICODE 等 一般可以使用文本编辑器直接打开
例如:数 5678 的以 ASCII 存储形式为: ASCII 码:00110101 00110110 00110111 00111000 歌词文件(lrc):文本文件
二进制文件:
基于值编码,自己根据具体应用,指定某个值是什么意思
把内存中的数据按其在内存中的存储形式原样输出到磁盘上
一般需要自己判断或使用特定软件分析数据格式
例如:数 5678 的存储形式为: 二进制码:00010110 00101110
文本文件的优点:
便于用户阅读,用于用户查看
二进制文件的优点:
不需要转换, 文件移动、拷贝、加密
知识点3【文件指针】(了解)
知识点4【操作文件的库函数】(了解)
1、fopen打开文件
#include <stdio.h>
FILE *fopen(const char *path, const char *mode);
mode
读写权限:r读 w写 a追加 +可读可写 t文本文件(省略) b二进制文件
r:以只读方式打开文件
文件不存在返回 NULL;
文件存在返回文件指针,进行后续的读操作
w:以只写方式打开文件
文件不存在,以指定文件名创建此文件,并且打开文件;
若文件存在,清空文件内容,打开文件,然后进行写操作;
如果文件打不开(比如文件只读),返回 NULL
a:以追加方式打开文件
文件不存在,以指定文件名创建此文件(同 w)
若文件存在,从文件的结尾处进行写操作
2、关闭文件 fclose
#include <stdio.h>
int fclose(FILE *fp);
3、一次读写一个字符
int fgetc(FILE *stream)//读操作
返回值:
以 t 的方式: 读到文件结尾返回 EOF
以 b 的方式:读到文件结尾,使用 feof(后面会讲)
int fputc(int c, FILE *stream)//写操作
fputc 将 c 的值写到 stream
返回值:
如果输出成功,则返回输出的字节值;
如果输出失败,则返回一个 EOF
EOF 是在 stdio.h 文件中定义的符号
案例1:fputc写操作
void test01()
{
FILE *fp = NULL;
fp = fopen("a.txt", "w");
if(fp == NULL)
{
perror("fopen");
return;
}
char buf[1024]="";
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1] = 0;
int i=0;
while(buf[i] != '\0')
{
fputc(buf[i++], fp);
}
fclose(fp);
}
案例2:fgetc读操作
void test02()
{
FILE *fp = NULL;
fp = fopen("a.txt", "r");
if(fp == NULL)
{
perror("fopen");
return;
}
char buf[1024]="";
int i=0;
while((buf[i++] = fgetc(fp)) != EOF);
buf[strlen(buf)-1]=0;
printf("%s\n", buf);
fclose(fp);
}
4、一次读写一个字符串
读操作
char *fgets(char *s, int size, FILE *stream)
从 stream 所指的文件中读取字符,在读取的时候碰到换行符或者是碰到文件的末尾停止读取。
或者是读取了 size-1 个字节停止读取,在读取的内容后面会加一个\0,作为字符串的结尾
返回值:
成功返回目的数组的首地址,即 s
失败返回 NUL
案例1:读操作
void test02()
{
FILE *fp = NULL;
fp = fopen("a.txt", "r");
if(fp == NULL)
{
perror("fopen");
return;
}
char buf[1024]="";
while(fgets(buf, sizeof(buf), fp) != NULL)
{
printf("##%s##\n", buf);
printf("##%d##\n", strlen(buf));
}
fclose(fp);
}
int fputs(const char *s, FILE *stream);
案例2:写操作
void test03()
{
FILE *fp = NULL;
fp = fopen("c.txt", "w");
if(fp == NULL)
{
perror("fopen");
return;
}
char *buf[]={"hello world\n", "hello world\n", "hello world"};
int n = sizeof(buf)/sizeof(buf[0]);
int i=0;
for ( i = 0; i < n; i++)
{
fputs(buf[i], fp);
}
fclose(fp);
}
5、文件块的读写fread fwrite 内存数据原样 输出到磁盘
返回的是整块数 不足一块 不算的
文件块的写
void test04()
{
HERO hero_buf[]={{"德玛西亚", 80, 60}, {"小炮", 40, 80}, {"小法",50, 90}};
FILE *fp = NULL;
fp = fopen("hero.txt", "w");
if(fp == NULL)
{
perror("fopen");
return;
}
fwrite(hero_buf, sizeof(HERO), 3, fp);
fclose(fp);
}
fwrite将内存数据原样输出到磁盘 而编辑器打开文件时 做了ASCII转换 会出现乱码
不方便用户查看 但不影响用户读文件数据
文件块的写
void test05()
{
HERO hero_buf[3];
memset(hero_buf, 0, sizeof(hero_buf));
FILE *fp = NULL;
fp = fopen("hero.txt", "r");
if(fp == NULL)
{
perror("fopen");
return;
}
fread(hero_buf, sizeof(HERO), 3, fp);
int i=0;
for ( i = 0; i < 3; i++)
{
printf("%s %d %d\n", hero_buf[i].name, hero_buf[i].def,hero_buf[i].atk);
}
fclose(fp);
}
fread fwrite用于文件的拷贝、移动 一般不用于用户查看
6、文件块的格式化读写fprintf(写) fscanf(读)
案例
void test06()
{
HERO hero_buf[]={{"德玛西亚", 80, 60}, {"小炮", 40, 80}, {"小法",50, 90}};
FILE *fp = NULL;
fp = fopen("hero.txt", "w");
if(fp == NULL)
{
perror("fopen");
return;
}
int i=0;
for ( i = 0; i < 3; i++)
{
fprintf(fp,"姓名:%s 防御:%d 攻击:%d\n", \
hero_buf[i].name,hero_buf[i].def,hero_buf[i].atk);
}
fclose(fp);
}
void test07()
{
HERO hero_buf[3];
memset(hero_buf, 0, sizeof(hero_buf));
FILE *fp = NULL;
fp = fopen("hero.txt", "r");
if(fp == NULL)
{
perror("fopen");
return;
}
int i=0;
for ( i = 0; i < 3; i++)
{
fscanf(fp,"姓名:%s 防御:%d 攻击:%d\n", \
hero_buf[i].name, &hero_buf[i].def,&hero_buf[i].atk);
}
for ( i = 0; i < 3; i++)
{
printf("%s %d %d\n", hero_buf[i].name, hero_buf[i].def,hero_buf[i].atk);
}
fclose(fp);
}
总结:
字节操作:fgetc fputc
字符串操作:fgets fputs
块操作:fread fwrite
格式化操作:fscanf fprintf
知识点5【文件的随机读写】(重要)
文件默认 顺序读写
知识点的引入:
void test01()
{
FILE *fp = NULL;
fp = fopen("c.txt", "w+");
if(fp == NULL)
{
perror("fopen");
return;
}
fputs("hello world", fp);
fclose(fp);
fp = fopen("c.txt", "r");
char buf[1024]="";
fgets(buf, sizeof(buf), fp);
printf("buf=%s\n",buf);
fclose(fp);
}
文件的随机读写:移动文件的流指针
rewind ftell fseek
1、rewind 复位文件流指针
void rewind(FILE *stream)
void test01()
{
FILE *fp = NULL;
fp = fopen("c.txt", "w+");
if(fp == NULL)
{
perror("fopen");
return;
}
fputs("hello world", fp);
//复位文件流指针
rewind(fp);
char buf[1024]="";
fgets(buf, sizeof(buf), fp);
printf("buf=%s\n",buf);
fclose(fp);
}
2、ftell 测文件读写位置距文件开始有多少个字节
long ftell(FILE *stream);
void test01(){
FILE *fp = NULL;
fp = fopen("c.txt", "w+");
if(fp == NULL){
perror("fopen");
return;
}
fputs("hello world", fp);
int len = 0;
len = ftell(fp);
printf("len = %d\n", len);
fclose(fp);
}
int main(int argc, char const *argv[])
{
test01();
return 0;
}
3、fseek 定位位置指针(读写位置)
int fseek(FILE *stream, long offset, int whence)
案例1:将文件流指针 定位到文件的尾部
fseek(fp, 0, 2);
案例2:将文件数据 一次性读取到内存
#include <stdlib.h>
#include <string.h>
void test02()
{
FILE *fp = NULL;
fp = fopen("a.txt", "r");
if(fp == NULL)
{
perror("fopen");
return;
}
//获取文件总大小
fseek(fp, 0, 2);//将文件流指针 定位到文件尾部
long len = ftell(fp);//获取文件的大小
rewind(fp);//复位文件流指针(方便后续读取文件数据)
printf("len = %ld\n", len);
//根据文件总大小申请空间
unsigned char *data = NULL;
data = (unsigned char *)calloc(1, len+1);
fread(data, len, 1, fp);
printf("%s\n", data);
free(data);
fclose(fp);
}
综合案例:文件加密器
详细设计API设计参考
1、从键盘获取源文件和目的文件名字
/**************************************************************************/
//函数功能:获取 目的文件和源文件的名字
//参数: src_file_name:源文件名字字符数组首地址。
// dest_file_name:目的文件的名字字符数组首地址
/**************************************************************************/
void get_file_name(char * dest_file_name,char * src_file_name)
2、从文件中读出内容
/**************************************************************************/
//函数功能:读出文件内容
//参数:file_length:整型指针,此地址中保存文件字节数。
// src_file_name:文件名字,从此文件中读取内容。
// 返回值:读出字符串的首地址
// 在此函数中测文件的大小,并malloc空间,再把文件内容读出返回,读出字符数组的首地址
/**************************************************************************/
char * read_src_file(unsigned long int *file_length,char *src_file_name)
3、字符数组加密
/**************************************************************************/
//函数功能:加密字符串
//参数:
// src_file_text:要加密的字符串。 length:字符串的长度
// password: 加密密码
// 返回值: 加密后的字符串的首地址
// 加密原理字符数组中每个元素加上password
/**************************************************************************/
char * file_text_encrypt(char * src_file_text,unsigned long int length,unsigned int password)
4、解密字符串
/**************************************************************************/
//函数功能:解密字符串
//参数:
// src_file_text:要解密的字符串。 length:字符串的长度
// password: 解密密码
// 返回值: 解密后的字符串的首地址
//思想;把数组中的每个元素减去password 给自己赋值。
/**************************************************************************/
char * file_text_decrypt(char * src_file_text,unsigned long int length,unsigned int password)
5、保存文件
/**************************************************************************/
//函数功能:将字符串保存到目的文件中
//参数:
// text:要保存的字符串首地址
// file_name :目的文件的名字
// length:字符串的长度
//思想:传入字符数组的首地址和数组的大小及保存后的文件的名字,即可保存数组到文件中
/**************************************************************************/
void save_file(char* text,unsigned long int length,char * file_name)
6、帮助信息
/**************************************************************************/
//
// 函数功能:打印帮助信息
//
//
/**************************************************************************/
void print_help()
{
printf("********1:加密文件***********\n");
printf("********2:解密文件***********\n");
printf("********3:退出程序***********\n");
}
废话不多说了上程序(完全注释):
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/**************************************************************************/
//函数功能:获取 目的文件和源文件的名字
//参数: src_file_name:源文件名字字符数组首地址。
// dest_file_name:目的文件的名字字符数组首地址
/**************************************************************************/
void get_file_name(char * dest_file_name,char * src_file_name)
{
printf("请输入你的原文件名称(30个字符):"); //打印提示信息
scanf("%s",src_file_name); //输入源文件名src_file_name
printf("请输入你的目标文件名称(30个字符):"); //打印提示信息
scanf("%s",dest_file_name); //输入目的文件名dest_file_name
return;
}
/**************************************************************************/
//函数功能:读出文件内容
//参数:file_length:整型指针,此地址中保存文件字节数。
// src_file_name:文件名字,从此文件中读取内容。
// 返回值:读出字符串的首地址
// 在此函数中测文件的大小,并malloc空间,再把文件内容读出返回,读出字符数组的首地址
/**************************************************************************/
char * read_src_file(unsigned long int *file_length,char *src_file_name)
{
FILE *fp = fopen(src_file_name,"r"); //打开名叫src_file_name的源文件,文件指针给fp
if(fp == NULL) //判断文件是否开启成功
{
printf("打开 %s 失败\n",src_file_name); //打印打开失败信息
return NULL; //返回
}
fseek(fp,0,SEEK_END); //将流指针指向最后一个字符
*file_length = ftell(fp); //计算偏移长度(字节长度),返回给file_length
rewind(fp); //重置流指针
char *buf = (char *)calloc(1,*file_length+1); //申请对空间,存放文件内容
fread(buf, *file_length, 1, fp); //将文件全部内容拷贝到buf指向的空间
fclose(fp); //关闭文件
return buf; //返回堆空间地址
}
/**************************************************************************/
//函数功能:加密字符串
//参数:
// src_file_text:要加密的字符串。 length:字符串的长度
// password: 加密密码
// 返回值: 加密后的字符串的首地址
// 加密原理字符数组中每个元素加上password
/**************************************************************************/
char * file_text_encrypt(char * src_file_text,unsigned long int length,unsigned int password)
{
int n = 0; //用于for循环遍历
for(n = 0; n<length; n++) //for循环遍历所有字符
{
*(src_file_text+n) += password; //为字符加密
}
return src_file_text; //返回src_file_text
}
/**************************************************************************/
//函数功能:解密字符串
//参数:
// src_file_text:要解密的字符串。 length:字符串的长度
// password: 解密密码
// 返回值: 解密后的字符串的首地址
//思想;把数组中的每个元素减去password 给自己赋值。
/**************************************************************************/
char * file_text_decrypt(char * src_file_text,unsigned long int length,unsigned int password)
{
int n = 0; //用于for循环遍历
for(n = 0; n<length; n++) //for循环遍历所有字符
{
*(src_file_text+n) -= password; //为字符解密
}
return src_file_text; //返回src_file_text
}
/**************************************************************************/
//函数功能:将字符串保存到目的文件中
//参数:
// text:要保存的字符串首地址
// file_name :目的文件的名字
// length:字符串的长度
//思想:传入字符数组的首地址和数组的大小及保存后的文件的名字,即可保存数组到文件中
/**************************************************************************/
void save_file(char* text,unsigned long int length,char * file_name)
{
FILE *fp = fopen(file_name,"w"); //打开名叫file_name的源文件,文件指针给fp
if(fp == NULL) //判断打开是否成功
{
printf("打开 %s 失败\n",file_name); //打印失败提示
return; //返回
}
fwrite(text, length, 1, fp); //将text内容写入文件
fclose(fp); //关闭文件
return;
}
/**************************************************************************/
//
// 函数功能:打印帮助信息
//
//
/**************************************************************************/
void print_help()
{
printf("********1:加密文件***********\n");
printf("********2:解密文件***********\n");
printf("********3:退出程序***********\n");
}
int main(int argc, char const *argv[])
{
char dest_file_name[30] = "", src_file_name[30] = ""; //存放源文件名和目标文件名
char order = '\0'; //存放指令
char *src_file_text = NULL; //创建一个字符指针准备接收堆空间地址
unsigned long int length = 0; //记录字符串长度
unsigned int password = 0; //用于存放密码值
while(1) //死循环
{
print_help(); //打印提示信息
scanf("%c",&order); //接收指令字符
getchar(); //接收输入字符后面的\n
switch (order) //判断指令
{
case '1': //加密指令
get_file_name(dest_file_name, src_file_name); //输入源文件名和目标文件名
src_file_text = read_src_file(&length,src_file_name); //读取src_file_name文件中的全部内容放至申请到的堆区空间,返回空间地址到src_file_text
printf("请输入你的密码:"); //打印提示信息
scanf("%d",&password); //输入密码值保存在password中
getchar(); //接收输入字符后面的\n
src_file_text = file_text_encrypt(src_file_text, length, password); //进行字符串加密,并将字符串地址返回
save_file(src_file_text, length, dest_file_name); //将加密的字符串,保存到dest_file_name文件中
if(src_file_text != NULL)
{
free(src_file_text); //堆区空间释放
src_file_text = NULL;
}
break; //跳出
case '2':
get_file_name(dest_file_name, src_file_name); //输入源文件名和目标文件名
src_file_text = read_src_file(&length,src_file_name); //读取src_file_name文件中的全部内容放至申请到的堆区空间,返回空间地址到src_file_text
printf("请输入你的密码:"); //输入解密密码
scanf("%d",&password); //输入密码值保存在password中
getchar(); //接收输入字符后面的\n
src_file_text = file_text_decrypt(src_file_text, length, password); //进行字符串解密,并将字符串地址返回
save_file(src_file_text, length, dest_file_name); //将解密的字符串,保存到dest_file_name文件中
if(src_file_text != NULL)
{
free(src_file_text); //堆区空间释放
src_file_text = NULL;
}
break;
case '3':
exit(-1); //退出
break;
}
}
return 0;
}