17文件与流
文件是什么?
文件是外存数据的组织单位。一个文件对应一批存放在外存(如硬盘、软盘、U盘)的数据,计算机以及计算机的使用者通过文件名实现对文件的操作(如复制、删除、内容修改)。
C++把一个文件看成是一个字节序列。
C++的文件类型
1.文本文件(也称ASCII文件)。文件中每个字节的内容是ASCII码(0~127),便于阅读和编辑。文件名通常以.txt为后缀
2二进制文件。文件中每个字节的内容不限(八个二进制位的任意0/1组合),无法阅读和编辑。文件名通常以.dat为后缀
流是什么?
流是对文件中字节流向及顺序的描述。一个流对应一个正在工作的文件(指文件被打开后,被关闭前),实质上是计算机操作系统为文件建立的一个保存文件部分内容的缓冲区及有关控制信息。
用FILE结构操作文件
三部曲
1.打开一个已存在的文件或建立并打开一个新文件
关键函数: fopen
2.对该文件进行读/写操作
关键函数: fgetc、fputc、fgets、fputs、fscanf、fprintf、feof、 rewind、fseek、fread、fwrite
3.关闭该文件
关键函数: fclose
以上函数都在库文件stdio.h中定义
三部曲之一
函数原型:
FILE *fopen( const char *filename,
const char *mode );
filename——路径及文件名,如“c:\\xxs\\x1.txt”、”x2.txt”、”x3.dat”
mode——打开方式,如“r”、“r+”、“rb”、“rb+”
FILE * :文件指针
FILE是在库文件stdio.h中定义的一个结构类型。C++用该类型的结构描述一个流,其重要数据有:文件名、操作方式、文件及缓冲区当前位置、文件结束标记
三个特殊的文件指针
stdin、stdout、stderr(在库文件stdio.h中定义)
mode :
C++有12种不同的文件打开方式
三部曲之二:关键函数的原型
_CRTIMP int __cdecl fgetc(FILE *);
int fputc(int, FILE *);
char * fgets(char *, int, FILE *);
int fputs(const char *, FILE *);
int fscanf(FILE *,const char *, ...);
int fprintf(FILE *,const char *, ...);
int feof(FILE *);
void rewind(FILE *);
int fseek(FILE *, long, int);
size_t fread(void *, size_t,size_t, FILE *);
size_t fwrite(const void *,size_t, size_t, FILE *);
三部曲之二:关键函数举例
fgetc:从文件中读取一个字符
参数: 文件指针
fgetc( stdin ) 相当于 getchar()
fputc:向文件中写入一个字符
参数:拟写入的字符和文件指针
fputc( 'a' , stdout ) 相当于 putchar( 'a' )
fseek:修改文件位置指针
int fseek(FILE *, long, int);
第一个参数——文件指针
第二个参数——偏移量
第三个参数——基准,可以为SEEK_SET、SEEK_CUR和SEEK_END,分别表示文件的起始位置、当前位置和文件尾
三部曲之三
函数原型:
int fclose(FILE * );
例子1:使用FILE指针新建一个文本文件,写入了字符串"This is a test file. "
#include <stdio.h>
main()
{FILE *fptr; //定义FILE指针
//打开或创建文件
if ((fptr = fopen("test.txt","w"))
!= NULL)
{//往文件中写入字符串
fprintf(fptr, "This is a test file.");
fclose(fptr); //关闭文件
}
else printf("Open file error.\n");
return 0;
}
例子2:将例1创建的文件中的数据读出来
#include <stdio.h>
main()
{FILE *fptr; //定义FILE指针
int c;
if ((fptr = fopen("test.txt","r"))
!= NULL)
{c=fgetc(fptr);
while(!feof(fptr)) //注意feof的用法
{putchar(c);
c=fgetc(fptr);
}
fclose(fptr); //关闭文件
}
else printf("Open file error.\n");
return 0;
}
例子3:将字符、字符串、整数、浮点数、结构等类型的数据写入文件
#include <stdio.h>
struct Test
{ int a;
double b;
};
main()
{Test st;
st.a = 10;
st.b = 1.1;
FILE *fptr; //声明文件指针
if((fptr=fopen("writetest.dat","wb"))
!=NULL)
{ //以二进制方式写入数据
fwrite(&st, sizeof(st),1,fptr);
//以字符方式写入一个字符
fputc('a', fptr);
//以字符方式写入一个字符串
fputs("Beijing", fptr);
//以字符方式写入整数和浮点数
fprintf(fptr, " %d %f ", 23, 12.34);
//关闭文件
fclose(fptr);
}
else
printf("Open file error.\n");
return 0;
}
例子4:将例3创建的文件中的数据读出来
//文件main.cpp,读二进制文件
#include <stdio.h>
struct Test
{ int a;
double b;
};
main()
{Test st;
char s[20];
int m;
float n;
char c;
FILE *fptr;
if((fptr=fopen("writetest.dat","rb"))
!=NULL)
{fread(&st,sizeof(st),1,fptr);
c = fgetc(fptr);
fgets(s,8,fptr);
fscanf(fptr," %d %f ",&m,&n);
fclose(fptr);
printf("STRUCT st: a = %d, b = %f\n",
st.a, st.b);
printf("CHAR c = '%c'\n", c);
printf("STRING s = %s\n", s);
printf("INTEGER m = %d,
FLOAT n = %f\n", m, n);
}
else printf("File open error.\n");
return 0;
}
例子5:将例3创建的文件中的数据读出来,跳过字符'a'和字符串“Beijing”
//文件main.cpp,读文件
#include <stdio.h>
struct Test
{ int a;
double b;
};
main()
{Test st;
int m;
float n;
FILE *fptr;
if((fptr=fopen("writetest.dat","rb"))
!=NULL)
{fread(&st,sizeof(st),1,fptr);
//修改文件位置指针,跳过字符a和字符串Beijing
fseek(fptr,8,SEEK_CUR);
fscanf(fptr," %d %f ",&m,&n);
fclose(fptr);
printf("STRUCT st: a = %d, b = %f\n",
st.a, st.b);
printf("INTEGER m = %d,\nFLOAT n = %f\n“
,m, n);
}
else
printf("File open error.\n");
return 0;
}
使用类和对象操作文件
文件流类的继承关系
几个特殊的流对象
1.标准输入流对象cin (类istream的对象)
2.标准输出流对象cout
3.非缓冲标准错误流对象cerr
4、缓冲标准错误流对象clog(类ostream的对象)
三个文件流类
类ifstream——文件的输入
类ofstream——文件的输出
类fstream——文件的输入输出
上述三个类都在头文件fstream.h中定义
例子6:使用文件流对象新建或打开一个文件,并写入字符串"This is a test file. "
#include <fstream.h>
main()
{//声明文件流对象
ofstream outFile("outFile.txt",ios::out);
if (!outFile)
//使用错误流对象输出错误信息
cerr<<"Open or create file error."
<<endl;
else
//输出数据到与对象outFile 关联的文件中
outFile << "This is a test file.";
return 0;
}
例子6中的
ofstream outFile("outFile.txt",ios::out);
可以改写为:
ofstream outFile;
outFile.open("outFile.txt",ios::out);
或
ofstream outFile;
outFile.open("outFile.txt");
文件可以显式关闭:
outFile.close();
问题:声明对象时使用文件流类ifstream、ofstream、fstream中的哪一个?
解析:取决于文件的打开方式
例子7:使用文件流对象将整数、浮点数、字符串等类型的数据写入文件
#include <fstream.h>
main()
{ofstream
outFile ("outFile.txt", ios::out);
if (!outFile )
cerr<<"Open file or create file error."
<<endl;
else
{outFile <<5<<"string"<<" "<<1.2;
outFile.close();
}
return 0;
}
例子8:使用文件流对象读取上例中程序创建的文件数据,跳过字符串“string”
#include <fstream.h>
main()
{ifstream
inFile ("outFile.txt", ios::in);
int a; float c;
if (!inFile)
cerr<<"File open error."<<endl;
else
{inFile>>a; inFile.seekg(7,ios::cur);
inFile>>c;
cout<<"INT--"<<a<<endl<<"FLO--"
<<c<<endl;
inFile.close();
}
return 0;
}
例子9:使用文件保存和恢复类的对象
#include <fstream.h>
class Test
{public:
Test(int m, double n)
{a = m; b = n;}
void set(int m, double n)
{a = m; b = n;}
void show()
{cout<<"int--"<<a<<" double--"
<< b <<endl;
}
private:
int a;
double b;
};
main()
{
Test st(10,10.5);
cout<<"Object st:"<<endl;
st.show();
ofstream outFile("outFile.dat",ios::out|ios::binary);
if (!outFile )
cerr<<"Open file or create file error.“
<<endl;
else
{outFile.write((char *)&st,sizeof(st));
outFile.close();}
st.set(1, 2.3);
cout<<"After set, object st:"<<endl;
st.show();//输出int--1 double--2.3
//创建文件流对象,再次打开该文件用于读
ifstream infile("outFile.dat", ios::in|ios::binary);
if (! infile )
cerr<<"File open error."<<endl;
else
{//从文件中恢复对象st
infile.read((char *)&st,sizeof(st));
infile.close();
}
cout<<" After read from file:"<<endl;
st.show(); //输出int--10 double--10.5
return 0;
}