第1节 文件概述,文本、二进制文件区别
根据组织形式,人类把文件分为ASCII文件(文本文件)和二进制文件。
ASCII文件:每个字节存放一个ASCII码,表示一个字符,打开就能看懂里面的内容;
二进制文件:把内存中数据的存储形式原样输出到磁盘上存放。
【注】操作系统会根据文件的扩展名打开特定的编辑器,将其转换为人类能看懂的内容。
文件对于计算机来说都是二进制数据,但是人类可以选择通过文本方式写入还是二进制方式写入,打开也一样。
双击或者type、cat等方式就是通过文本方式打开文件,如果用代码或者加二进制标记打开文件,就是另一种。
人类所理解的二进制:
short int a = 10000;
int len = sizeof(a);
a = 10000;
在这里,观察内存可知0x009CF97C处存放的为10,0x009CF97D处存放的是27(两个十六进制数为8位二进制,代表一个字节,所以两个字节用来存放a,正好对应short int存储的a占两字节),因为计算机是小端存储,即高地址存放高位,低地址存放地位,所以存放的十六进制数实际为0x2710,即为十进制数的10000。
※ 10000存放的十六进制为31 30 30 30 30,计算机把10000看作五个字节,31对应十进制为49,对应ASCII码为‘1’。
第2节 文件的开、关、读、写
一、文件的打开
文件读写之前,必须要打开,读写之后,必须要关闭!
FILE *fp;
fp = fopen(文件名,使用文件的方式); //这两个参数都是字符串
如:fp = fopen("a.txt","r"); //只读打开a.txt
通过fopen,告诉系统打开的文件名(当前目录)、打开方式、指向被打开文件的指针名。
文件有个位置指针fgetc,当用追加指针打开文件时,位置指针指向文件末尾。
二、文件的关闭
问题:为什么要关闭?
a)释放该文件占用的FILE结构的内存单元;
b)关闭文件的动作会触发系统把缓冲区中的数据写入磁盘,避免了缓冲区数据丢失。
if(fp){
fclose(fp); //返回值一般没有用,一般不会失败
}
三、文件的读写简单讲
fputc():把一个字符写到磁盘文件上去,如果失败(比如是只读打开文件的),返回EOF(End of File,系统定义成-1),若成功,返回写入的字符的ASCII值。
fputc(ch,fp); //ch就是一个字符
fgetc():返回读入的字符,如果失败,返回EOF。
char reco = fgetc(fp);
//while (reco != EOF) { //判断是否读完
while(!feof(fp)){ //这样写更规范
putchar(reco);
reco = fgetc(fp);
}
其他的一些关于文件的函数:
四、文件读写实战操作
读取配置文件中的每一行元素并以字符串的形式展示出来!
FILE *fp = fopen("config.txt", "r");
if (!fp) {
cout << "文件打开失败" << endl;
}else {
char LineBuff[1024];
while (!feof(fp)) {
LineBuff[0] = 0; //相当于清空,但是经过测试好像fgets函数自己有清空第一个参数的功能
//读取一行,遇到0x0A结束,该函数把0x0D好像删除了,只剩下0x0A
if (fgets(LineBuff, sizeof(LineBuff) - 1, fp)==NULL) { //其实每次读的是第二个参数-1
//说明这行读的有问题
continue;
}
if (LineBuff[0] == 0)
continue;
//若LineBuff中有东西,必须删除最后的换行符'\n'
lblprocstring:
if (strlen(LineBuff) > 0) {
if (LineBuff[strlen(LineBuff) - 1] == 10 || LineBuff[strlen(LineBuff) - 1] == 13) {
LineBuff[strlen(LineBuff) - 1] = 0;
goto lblprocstring;
}
}
if (strlen(LineBuff) <= 0)
continue;
printf("%s\n", LineBuff);
} //end while
}
fclose(fp); //end if(!fp)
简单的文件读写代码(c++)
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
using namespace std;
int main()
{
//写入文件
string str;
cin>>str;
ofstream of;
of.open("a.txt");
of << str <<endl;
of.close();
//读出文件
ifstream ii;
ii.open("a.txt");
string temp;
vector<string> vec;
while(getline(ii,temp)){
vec.push_back(temp);
}
for(auto iter=vec.begin();iter!=vec.end();iter++){
cout << *iter <<endl;
}
ii.close();
return 0;
}
第3节 将结构体写入二进制文件再读出
一、将结构体写入二进制文件
fwrite:用于向文件中写入数据。
fwrite(buffer,size,count,fp);
buffer:要写到文件中去的数据的地址的存放位置;
size:要写入文件的一个结构体的字节数
count:有几个size字节数
如果fwrite失败,返回0,成功则返回count。
struct stu {
char name[20];
int age;
double score;
};
//main中
struct stu student[2];
strcpy(student[0].name, "张三abc");
student[0].age = 21;
student[0].score = 92.1f;
strcpy(student[1].name, "李四def");
student[1].age = 19;
student[1].score = 86.2f;
FILE *fp;
fp = fopen("structfile.bin", "wb");
if (!fp) {
cout << "文件打开失败" << endl;
}
else {
int result = fwrite(student, sizeof(struct stu), 2, fp);
fclose(fp);
}
【注意事项】
a)往文件里写的结构体中不要出现指针
b)vs编译器往往会多加几个字节凑8字节对齐,linux gcc编译器会多几个字节凑4字节对齐
解决方法:强行1字节对齐(不用对齐),在定义结构体前加#pragma pack(1),定义结构体后加#pragma pack()!
二、从二进制文件中读出结构体
fread(buffer,size,count,fp);
示例:
FILE *fp;
fp = fopen("structfile.bin", "rb");
if (!fp) {
cout << "文件打开失败" << endl;
}
else {
struct stu structnew[2];
int result = fread(structnew, sizeof(struct stu), 2, fp);
fclose(fp);
}