指程序与数据的交互是以流的形式进行的。进行 C 语言文件的存取时,
都会先进行“打开文件”操作,这个操作就是在打开数据流,而“关闭文件”操作就是关闭数据流。
指在程序执行时,所提供的额外内存,可用来暂时存放做准备执行的数据。它的设置是为了提高存取效率,因为内存的存取速度比磁盘驱动器快得多。
C++ 语言中带缓冲区的文件处理:
C++ 语言的文件处理功能依据系统是否设置“缓冲区”分为两种:一种是设置缓冲区,另一种是不设置缓冲区。当使用标准 I/O 函数(包含在头文件 cstdio 中)时,系统会自动设置缓冲区,并通过数据流来读写文件。 当进行文件读取时,不会直接对磁盘进行读取,而是先打开数据流,将磁盘上的文件信息拷贝到缓冲区内,然后程序再从缓冲区中读取所需数据,如下图所示:
分为文本文件和二进制文件两种。
文本文件:
是以字符编码的方式进行保存的,只是计算机以二进制表示数据在外部存储介质上的另一种存放形式。它所存放的每一个字节都可以转换为一个可读字符。当向文件中写入数据时,windows 中一旦遇到"换行"字符(ASCII 码为 10)则会转换成"回车-换行"(ASCII 值为 13,10)。在读取数据的时候,一遇到"回车-换行"的组合 ASCII 值为 13,10),则会转换成为"换行"字符(ASCII 码为 10)。
二进制文件:
将内存中数据原封不动的读取和写入文件中。二进制文件适用于非字符为主的数据。如果以记事本打开,只会看到一堆乱码。除了文本文件外,所有的数据都可以算是二进制文件。二进制文件的优点在于存取速度快,占用空间小,以及可随机存取数据。
包括顺序存取方式和随机存取方式两种。
顺序读取:
也就是从上往下,一笔一笔读取文件的内容。保存数据时,将数据附加在文件的末尾。这种存取方式常用于文本文件,而被存取的文件则称为顺序文件。
随机存取:
多半以二进制文件为主.它会以一个完整的单位来进行数据的读取和写入,通常以结构为单位。
如果要访问文件,要借助于文本变量,即文件指针 FILE *才可以完成。文件在进行读写操作之前要先打开,使用完毕要关闭。所谓打开文件,实际上是建立文件的各种有关信息,并使文件指针指向该文件,以便进行其它操作。关闭文件则断开指针与文件之间的联系,也就禁止再对该文件进行操作。
对文件的操作是由文件流类完成的。文件流类在流与文件间建立连接。由于文件流分为三种:文件输入流、文件输出流、文件输入/输出流,所以相应的必须将文件流说明为 ifstream、ofstream 和 fstream 类的对象,然后利用文件流的对象对文件进行操作。对文件的操作过程可按照一下四步进行:即定义文件流类的对象、打开文件、对文件进行读写操作、关闭文件。
//流类 流对象;
ifstream ifile; //定义一个文件输入流对象
ofstream ofile; //定义一个文件输出流对象
fstream iofile; //定义一个文件输出/输入流对象
定义了文件流对象后,就可以利用其成员函数 open()打开需要操作的文件,该成员函数的函数原为:
void open(const unsigned char *filename,int mode,int access=filebuf:openprot);
其中:filename 是一个字符型指针,指定了要打开的文件名;mode 指定了文件的打开方式,其值如下表所示;access 指定了文件的系统属性,取默认即可:
说明:
ios::in|ios::out 表示以读/写方式打开文件
ios::in|ios:: binary 表示以二进制读方式打开文件
ios::out|ios:: binary 表示以二进制写方式打开文件
ios::in|ios::out|ios::binary 表示以二进制读/写方式打开文件
对于 ifstream 流, mode 参数的默认值为 ios::in,
对于 ofstream 流,mode 的默 认值为 ios::out|ios::trunc,
对于 fstream 流, mode 的默认值为 ios::int|ios::out|ios::app
#include
#include
using namespace std;
int main()
{
ifstream ifs("xxx.txt",ios::in);
if(!ifs)
cout<<"open error1"<<endl;
char buf[100];
if(ifs>>buf)
cout<<buf<<endl;
ofstream ofs("yyy.txt",ios::out|ios::app);
if(!ofs)
cout<<"open error2"<<endl;
ofs<<"abcefldkj"<<endl;
fstream fs("zzz.txt",ios::in|ios::out|ios::app);
//app 有创建文件的功能 trunc 也有,但是清空
if(!fs)
cout<<"open error3"<<endl;
fs<<"abcdefg";
char buf[1024];
fs.seekg(0,ios::beg);
fs>>buf;
if(fs)
cout<<buf<<endl;
return 0;
}
在文件操作结束(即读、写完毕)时应及时调用成员函数 close()来关闭文件。该函数比较简单,没有参数和返回值。
系统为了标识当前文件操作的状态,提供了标识位和检查标识位的函数。
/// Indicates a loss of integrity in an input or output sequence (such
/// as an irrecoverable read error from a file).
static const iostate badbit =_S_badbit;
/// Indicates that an input operation reached the end of an input sequence.
static const iostate eofbit =_S_eofbit;
/// Indicates that an input operation failed to read the expected
/// characters, or that an output operation failed to generate the
/// desired characters.
static const iostate failbit =_S_failbit;
/// Indicates all is well.
static const iostate goodbit =_S_goodbit
eof()
如果读文件到达文件末尾,返回 true。
bad()
如果在读写过程中出错,返回 true 。例如:当我们要对一个不是打开为写状态的文件进行写入时,
或者我们要写入的设备没有剩余空间的时候。
fail()
除了与 bad() 同样的情况下会返回 true 以外,加上格式错误时也返回 true ,例如
当想要读入一个整数,而获得了一个字母的时候。或是遇到 eof。
good()
这是最通用的:如果调用以上任何一个函数返回 true 的话,此函数返回 false 。
clear()
标识位一旦被置位,这些标志将不会被改变,要想重置以上成员函数所检查的状态标志,
你可以使用成员函数 clear(),没有参数。比如:通过函数移动文件指针,并不会使 eofbit自动重置
#include
using namespace std;
int main()
{
int integerVal;
cout << "Before a bad input operation:"
<< "\n cin.eof(): " <<cin.eof()
<< "\n cin.fail(): " <<cin.fail()
<< "\n cin.bad(): " <<cin.bad()
<< "\n cin.good(): " <<cin.good()<<endl;
cin>>integerVal; // control + D/Z
cout << "After a bad input operation:"
<< "\n cin.eof(): " <<cin.eof()
<< "\n cin.fail(): " <<cin.fail()
<< "\n cin.bad(): " <<cin.bad()
<< "\n cin.good(): " <<cin.good()<<endl;
cin.clear();
cout<< "\n cin.eof(): " <<cin.eof()
<< "\n cin.fail(): " <<cin.fail()
<< "\n cin.bad(): " <<cin.bad()
<< "\n cin.good(): " <<cin.good()<<endl;
}
在打开文件后就可以对文件进行读写操作了。从一个文件中读出数据,可以使用文件流类的 get、getline、read 成员函数以及运算符“>>”;
而向一个文件写入数据,可以使用其 put、write 函数以及插入符“<<”;
读出
operator>>
int get();
istream& get(int);
istream & get(char*,int n, char deli )
istream& getline(char * ,int n)
写入
operator<<
osream put(int)
#include
#include
using namespace std;
int main()
{
fstream ifs("src.txt",ios::in);
if(!ifs)
{
cout<<"open error"<<endl;
return -1;
}
fstream ofs("dest.txt",ios::out|ios::trunc);
if(!ofs)
{
cout<<"open error"<<endl;
return -1;
}
// char ch;
// while(ifs.get(ch),!ifs.eof())
// {
// ofs.put(ch);
// }
// ifs.close();
// ofs.close();
char buf[1024];
while(ifs.get(buf,1024,'\n'))
{
while(ifs.peek() == '\n')
ifs.ignore();
ofs<<buf<<endl;
}
ifs.close();
ofs.close();
return 0;
}
ostream & write(const char * buffer,int len);
istream & read(char * buff, int len);
#include
#include
using namespace std;
struct Student
{
char name[100];
int num;
int age;
char sex;
};
int main()
{
Student s[3] = {
{"li",1001,18,'f'},
{"Fun",1002,19,'m'},
{"Wang",1004,17,'f'}
};
ofstream ofs("student.data",ios::out|ios::trunc|ios::binary);
if(!ofs){
cout<<"open error"<<endl;
}
for(int i=0; i<3; i++)
{
ofs.write((char*)&s[i],sizeof(s[i]));
}
ofs.close();
Student s;
ifstream ifs("student.data",ios::int|ios::binary);
if(!ifs)
cout<<"open error"<<endl;
ifs.seekg(sizeof(stu),ios::beg);
while(ifs.read((char*)&s,sizeof(Student)),!ifs.eof())
{
cout<<"Name "<<s.name<<endl;
cout<<"Num "<<s.num<<endl;
cout<<"Age "<<s.age<<endl;
cout<<"Sex "<<s.sex<<endl;
cout<<"---------------"<<endl;
}
ifs.close();
return 0;
}
在判断文件打开成功与否或是连续从流中读取数据时,就要用到对流对像的操作,比如if(!cin) 或是 whie(cin) 等等。
代码 while(cin>>val),我们都知道 cin 是一个流对象,而>>运算符返回左边的流对象,也就是说 cin>>val 返回 cin,于是 while(cin>>val)就变成了 while(cin),问题就变成了一个
流对象在判断语句中的合法性。
不管是 while(cin)还是 if(cin),都是合法的,为什么呢?我们自己定义一个类,然后定义该类的对象,然后使用 if 语句来判断它是不合法的。这说明,流对象具有某种转换函数,可
以将一个流对象转换成判断语句可以识别的类型。打开 iostream.h 文件,找到 cin 的定义,发现是来自于istream.h,其中的模板类basic_istream 继承自 basic_ios,打开 basic_ios 的定义,发现它有两个重载函数。operator void *() const 和 bool operator!() const。这两个函数使得流对象可作为判断语句的内容。
operator void*() const //转化函数
{
return this->fail() ? 0 : const_cast<basic_ios*>(this);
}
bool operator!() const
{
return this->fail();
}
因此,可以简单的理解调用过程为:
while(cin) =====> while(!cin.fail()) //while the stream is OK
while(!cin) =====> while(cin.fail()) //while the stream is NOT OK