本篇文章主要讲解C++中的文件操作的相关简介。
一.C++文件简介
c++支持以下两种文件类型:
1.文本文件,又称ASCII字符文件,其每一个字节存放一个ASCII字符。
2.二进制文件,把内存中的数据原样存放到磁盘上。
一个标准的C++文件是一个字节流或者二进制流,将数据当作是一连串的字符。在C++中,对文件的存取是以字符(或字节数)为单位的,这样的文件称为流式文件。
二.文件的打开和关闭
要访问一个文件,我们需要创建一个文件指针。声明方式为:FILE* fp;
指针fp指向FILE结构,用于存放文件信息包括文件名、文件状态和当前位置等。
1.C++中提供fopen函数用于打开一个文件,函数的声明原型如下:
FILE *fopen(const char *filename,const char *mode);
参数简介:
1).filename:指定文件名称
2).mode:指定文件打开方式。方式有以下几种:
“r”":只读方式,为输入打开一个文本文件。
“w”:只写方式,为输出打开一个文本文件。
“a”:追加方式,向文本文件的末尾添加数据。
“rb”:只读方式,为输入打开一个二进制文件。
“wb”:只写方式,为输出打开一个二进制文件。
“ab”:追加方式,向二进制文件的末尾添加数据。
“r+”:读写方式,为读写打开一个文本文件。
“w+”:读写方式,为读写新建一个文本文件。
“a+”:读写方式,为读写打开一个文本文件。
“rb+”:读写方式,为读写打开一个二进制文件。
“wb+”:读写方式,为读写新建一个二进制文件。
“ab+”:读写方式,为读写打开一个二进制文件。
以上的文件打开方式只需要记录,等用的时候再找出需要的方式。
在打开并使用完一个文件后,我们需要关闭它。
C++提供fclose函数用于关闭一个文件,函数的声明如下:
int fclose(FILE *stream);
参数说明:
stream:用于指向文件流对象。
文件访问实例演示:
#include<stdio.h>
#include<iostream>
using namespace std;
int main(){
FILE* fp;
fp=fopen("D:\\TestFile\\Readme.txt","r+");
if(fp!=NULL)
{
cout<<"文件存在"<<endl;
}
else
{
cout<<"文件不存在"<<endl;
}
fclose(fp);
return 0;
}
先在对应位置创建文件。
运行结果:
再看下文件打开方式"w+"。删除Readme.txt后,会自动生成Readme.txt。
fp=fopen("D:\\TestFile\\Readme.txt","w+");
结果:
其它打开方式,大家可以自行演示。
三.文件的读写
C++提供了文件读写函数,调用fputc函数可以把一个字符写到文件中,调用fgetc函数可以从文件中读取一个字符。
fputc函数和fgetc函数声明如下:
int fputc(int c,FILE* stream);
int fgetc(FILE* stream);
参数说明:
c:指定写入文件的字符。
stream:文件流指针对象。
文件写入字符演示:
#include<stdio.h>
#include<iostream>
using namespace std;
int main(){
FILE* fp;
fp=fopen("D:\\TestFile\\Readme.txt","r+");
if(fp!=NULL)
{
cout<<"文件存在"<<endl;
fputc('a',fp);//写入字符a
fputc('b',fp);//写入字符b
}
else
{
cout<<"文件不存在"<<endl;
}
fclose(fp);
fp=fopen("D:\\TestFile\\Readme.txt","r+");
if(fp!=NULL)
{
char ch;
while(!feof(fp))
{
ch=fgetc(fp);
printf("%c",ch);
}
}
fclose(fp);
printf("\n\n");
return 0;
}
结果:
字符a和b都写进文件中了并且可以读取。
单个单个字符写进文件效率低且代码量很大,如果需要读写文件中的一组字符,可以调用标准函数fread和fwrite。函数声明如下:
size_t fread(void *buffer,size_t size,size_t count,FILE *stream);
size_t fwrite(const void *buffer,size_t size,size_t count,FILE *stream);
参数说明:
1).buffer:指定数据存放缓冲区。
2).size:指定读写的字节数。
3).count:指定读写的数据项,以size参数指定的字节数为单位。
4).stream:文件流指针。
size_t在C语言中就有了。
它是一种“整型”类型,里面保存的是一个整数,就像int、long那样。这种整数用来记录一个大小(size)。size_t的全称应该是size type,就是说“一种用来记录大小的数据类型”。
通常我们用sizeof(XXX)操作,这个操作所得到的结果就是size_t类型。
读写一组字符串字符实例演示:
class Info
{
public:
char Name[10];
char Address[10];
char Post[10];
Info()
{
strcpy(Name,"");
strcpy(Address,"");
strcpy(Post,"000000");
}
Info(char* name,char* address,char* post)
{
strcpy(Name,name);
strcpy(Address,address);
strcpy(Post,post);
}
};
int main(){
FILE* fp;
Info info1("张三","北京","100085");
fp=fopen("Info.txt","wb");
if(fp!=NULL)
{
fwrite(&info1,sizeof(Info),1,fp);
}
fclose(fp);
Info info2;
fp=fopen("Info.txt","rb");
if(fp!=NULL)
{
fread(&info2,sizeof(Info),1,fp);
}
printf("Info2:%s,%s,%s\n",info2.Name,info2.Address,info2.Post);
fclose(fp);
printf("\n\n");
return 0;
}
结果:
发现读出文件没问题,但是生成的文件里变成了乱码,这是什么原因呢?
查找资料发现解释如下:
fwrite是二进制写入,而我们使用记事本查看就是乱码。
如何修改呢?
我们可以使用fprintf来替换fwrite。
将fwrite部分修改为:
fprintf(fp,"%s %s %s\n",info1.Name,info1.Address,info1.Post);
运行:
四.文件的定位
文件中的位置指针保存了当前读写的位置,每次读写一个字符后,该位置指针自动指向下一个字符位置。
使用rewind函数可以将位置指针定位到文件开头,调用fseek函数可以定位到文件中的任何位置。函数声明如下:
void rewind(FILE *stream);
int fseek(FILE *stream,long offset,int origin);
long ftell(FILE *stream);
参数说明:
stream:指定文件指针。
offset:指定位移量,即移动的字节数。
origin:定位起点:
SEEK_CUR 从文件当前位置开始
SEEK_END 从文件结尾开始
SEEK_SET 从文件开头开始
示例:
int main()
{
FILE* fp
Info info1("张三","北京","111111");
Info info2("李四","上海","222222");
Info info3;
Info info4;
Info info5;
fp=fopen("Info.txt","wb");
if(fp!=NULL)
{
fwrite(&info1,sizeof(Info),1,fp);
fwrite(&info2,sizeof(Info),1,fp);
}
fclose(fp);
fp=fopen("Info.txt","rb");
if(fp!=NULL)
{
fread(&info3,sizeof(Info),1,fp);
fread(&info4,sizeof(Info),1,fp);
printf("Info3:%s,%s,%s\n",info3.Name,info3.Address,info3.Post);
printf("Info4:%s,%s,%s\n",info4.Name,info4.Address,info4.Post);
}
fclose(fp);
printf("\n\n");
fp=fopen("Info.txt","rb");
if(fp!=NULL)
{
fseek(fp,sizeof(Info),SEEK_SET);
fread(&info5,sizeof(Info),1,fp);
printf("Info5:%s,%s,%s\n",info5.Name,info5.Address,info5.Post);
}
return 0;
}
结果:
从文件开头开始,定位到第二条记录位置。将SEEK_SET换为SEEK_END.
结果:
从文件结尾开始定位。
补充:文件的写和读顺序是一一对应的,比如:
fwrite 第一串字符
fwrite 第二串字符
fread 第一串字符
fread 第二串字符
如果交换位置
fwrite 第二串字符
fwrite 第一串字符
fread 第二串字符
fread 第一串字符