C++ 文件IO流

1. C的IO流

1.1 数据流

指程序与数据的交互是以流的形式进行的。进行 C 语言文件的存取时,
都会先进行“打开文件”操作,这个操作就是在打开数据流,而“关闭文件”操作就是关闭数据流。

1.2 缓冲区

指在程序执行时,所提供的额外内存,可用来暂时存放做准备执行的数据。它的设置是为了提高存取效率,因为内存的存取速度比磁盘驱动器快得多。
C++ 语言中带缓冲区的文件处理:
C++ 语言的文件处理功能依据系统是否设置“缓冲区”分为两种:一种是设置缓冲区,另一种是不设置缓冲区。当使用标准 I/O 函数(包含在头文件 cstdio 中)时,系统会自动设置缓冲区,并通过数据流来读写文件当进行文件读取时,不会直接对磁盘进行读取,而是先打开数据流,将磁盘上的文件信息拷贝到缓冲区内,然后程序再从缓冲区中读取所需数据,如下图所示:

文件读
文件写

1.3 文件类型

分为文本文件二进制文件两种。
文本文件:
是以字符编码的方式进行保存的,只是计算机以二进制表示数据在外部存储介质上的另一种存放形式。它所存放的每一个字节都可以转换为一个可读字符。当向文件中写入数据时,windows 中一旦遇到"换行"字符(ASCII 码为 10)则会转换成"回车-换行"(ASCII 值为 13,10)。在读取数据的时候,一遇到"回车-换行"的组合 ASCII 值为 13,10),则会转换成为"换行"字符(ASCII 码为 10)。
二进制文件:
内存中数据原封不动的读取和写入文件中二进制文件适用于非字符为主的数据。如果以记事本打开,只会看到一堆乱码。除了文本文件外,所有的数据都可以算是二进制文件二进制文件的优点在于存取速度快,占用空间小,以及可随机存取数据

1.4 文件存取方式

包括顺序存取方式和随机存取方式两种。
顺序读取
也就是从上往下,一笔一笔读取文件的内容。保存数据时,将数据附加在文件的末尾。这种存取方式常用于文本文件,而被存取的文件则称为顺序文件。
随机存取
多半以二进制文件为主.它会以一个完整的单位来进行数据的读取和写入,通常以结构为单位。

1.5 借助文件指针读写文件

如果要访问文件,要借助于文本变量,即文件指针 FILE *才可以完成。文件在进行读写操作之前要先打开,使用完毕要关闭。所谓打开文件,实际上是建立文件的各种有关信息,并使文件指针指向该文件,以便进行其它操作。关闭文件则断开指针与文件之间的联系,也就禁止再对该文件进行操作

1.6 操作流程图

流程图

2. C++ 文件IO流

2.1 文件流类与文件流对象

对文件的操作是由文件流类完成的。文件流类在流与文件间建立连接。由于文件流分为三种:文件输入流、文件输出流、文件输入/输出流,所以相应的必须将文件流说明为 ifstream、ofstream 和 fstream 类的对象,然后利用文件流的对象对文件进行操作。对文件的操作过程可按照一下四步进行:即定义文件流类的对象、打开文件、对文件进行读写操作、关闭文件

2.2 文件的打开和关闭

2.2.1 定义流对象

//流类 流对象;
ifstream ifile; //定义一个文件输入流对象
ofstream ofile; //定义一个文件输出流对象
fstream iofile; //定义一个文件输出/输入流对象

2.2.2 打开文件

定义了文件流对象后,就可以利用其成员函数 open()打开需要操作的文件,该成员函数的函数原为:

void open(const unsigned char *filename,int mode,int access=filebuf:openprot);

其中:filename 是一个字符型指针,指定了要打开的文件名;mode 指定了文件的打开方式,其值如下表所示;access 指定了文件的系统属性,取默认即可:
打开方式
说明:

  1. 在实际使用过程中,可以根据需要将以上打开文件的方式用“|”组合起来。如:
ios::in|ios::out 表示以读/写方式打开文件
ios::in|ios:: binary 表示以二进制读方式打开文件
ios::out|ios:: binary 表示以二进制写方式打开文件
ios::in|ios::out|ios::binary 表示以二进制读/写方式打开文件
  1. 如果未指明以二进制方式打开文件,则默认是以文本方式打开文件。
对于 ifstream 流, mode 参数的默认值为 ios::in,
对于 ofstream 流,mode 的默 认值为 ios::out|ios::trunc,
对于 fstream 流, mode 的默认值为 ios::int|ios::out|ios::app
  1. 也可以通过,构造函数打开文件。
  2. 出错处理是通过,对类对象进行判断的。若文件打开成功,返回 1,否则返回
#include <iostream>
#include <fstream>
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;
}

2.2.3 文件的关闭

在文件操作结束(即读、写完毕)时应及时调用成员函数 close()来关闭文件。该函数比较简单,没有参数和返回值。

2.4 流文件状态与判断

系统为了标识当前文件操作的状态,提供了标识位和检查标识位的函数。

2.4.1 标识位

/// 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

2.4.2 函数

eof()
如果读文件到达文件末尾,返回 true
bad()
如果在读写过程中出错,返回 true 。例如:当我们要对一个不是打开为写状态的文件进行写入时,
或者我们要写入的设备没有剩余空间的时候。
fail()
除了与 bad() 同样的情况下会返回 true 以外,加上格式错误时也返回 true ,例如
当想要读入一个整数,而获得了一个字母的时候。或是遇到 eof。
good()
这是最通用的:如果调用以上任何一个函数返回 true 的话,此函数返回 false
clear()
标识位一旦被置位,这些标志将不会被改变,要想重置以上成员函数所检查的状态标志,
你可以使用成员函数 clear(),没有参数。比如:通过函数移动文件指针,并不会使 eofbit自动重置
#include <iostream>
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;
}

输出结果
输出结果

2.5 文件的读写操作

在打开文件后就可以对文件进行读写操作了。从一个文件中读出数据,可以使用文件流类的 get、getline、read 成员函数以及运算符“>>”;

而向一个文件写入数据,可以使用其 put、write 函数以及插入符“<<”;

2.5.1 读写文本文件

读出

operator>>
int get();
istream& get(int);
istream & get(char*,int n, char deli )
istream& getline(char * ,int n)

写入

operator<<
osream put(int)
#include <iostream>
#include <fstream>
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;
}

2.5.2 读写二进制文件

ostream & write(const char * buffer,int len);
istream & read(char * buff, int len);
#include <iostream>
#include <fstream>
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;
}

3. (cin)和(!cin)的原理

在判断文件打开成功与否或是连续从流中读取数据时,就要用到对流对像的操作,比如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
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值