C++基础教程面向对象(学习笔记(106))

基本文件I / O

C ++中的文件I / O与普通I / O非常相似(有一些小的复杂性)。C ++中有3个基本文件I / O类:ifstream(派生自istream),ofstream(派生自ostream)和fstream(派生自iostream)。这些类分别进行文件输入,输出和输入/输出。要使用文件I / O类,您需要包含fstream标头。

与已经可以使用的cout,cin,cerr和clog流不同,文件流必须由程序员明确设置。但是,这非常简单:打开一个文件进行读取和/或写入,只需实例化相应文件I / O类的对象,并将文件名作为参数。然后使用插入(<<)或提取(>>)运算符来写入或读取文件中的数据。完成后,有几种方法可以关闭文件:显式调用close()函数,或者让文件I / O变量超出范围(文件I / O类析构函数将为您关闭文件) 。

文件输出

要在以下示例中执行文件输出,我们将使用ofstream类。这非常简单:

#include <fstream>
#include <iostream>
#include <cstdlib> //exit()
 
int main()
{
    using namespace std;
 
    // ofstream用于写入文件
    // 我们将创建一个名为Sample.dat的文件
    ofstream outf("Sample.dat");
 
    //如果我们无法打开输出文件流进行写入
    if (!outf)
    {
        // 打印错误并且退出
        cerr << "Uh oh, Sample.dat could not be opened for writing!" << endl;
        exit(1);
    }
 
    // 我们将在这个文件中写入两行
    outf << "This is line 1" << endl;
    outf << "This is line 2" << endl;
 
    return 0;
	
    // 当超出范围
    //  这个ofstream析构函数将关闭这个文件
}

如果查看项目目录,应该会看到一个名为Sample.dat的文件。如果用文本编辑器打开它,你会发现它确实包含我们写入文件的两行。

请注意,也可以使用put()函数将单个字符写入文件。

文件输入

现在,我们将获取我们在上一个示例中编写的文件,并从磁盘中读回来。请注意,如果我们已到达文件末尾(EOF),ifstream将返回0。我们将使用这个事实来确定要阅读多少。

#include <fstream>
#include <iostream>
#include <string>
#include <cstdlib> // exit()
 
int main()
{
    using namespace std;
 
    // ifstream用于读取文件
    // 我们将从一个名为Sample.dat的文件中读取
    ifstream inf("Sample.dat");
 
    //如果我们无法打开输出文件流进行读取
    if (!inf)
    {
        // 打印错误并且退出
        cerr << "Uh oh, Sample.dat could not be opened for reading!" << endl;
        exit(1);
    }
 
    // 虽然还有东西可以read
    while (inf)
    {
        // 将文件中的内容读入字符串并打印出来
        std::string strInput;
        inf >> strInput;
        cout << strInput << endl;
    }
    
    return 0;
	
    // 当超出范围
    //  这个ofstream析构函数将关闭这个文件
}

这会产生结果:

This
is
line
1
This
is
line
2

嗯,那不是我们想要的。请记住,提取运算符处理“格式化输出”,并在空白处打破。为了读取整行,我们必须使用getline()函数。

#include <fstream>
#include <iostream>
#include <string>
#include <cstdlib> // exit()
 
int main()
{
    using namespace std;
 
    // ifstream用于读取文件
    // 我们将从一个名为Sample.dat的文件中读取
    ifstream inf("Sample.dat");
 
    // 如果我们无法打开输入文件流进行读取
    if (!inf)
    {
        // 打印错误并且退出
        cerr << "Uh oh, Sample.dat could not be opened for reading!" << endl;
        exit(1);
    }
 
    // 虽然还有一些东西需要阅读
    while (inf)
    {
        // 将文件中的内容读入字符串并打印出来
        std::string strInput;
        getline(inf, strInput);
        cout << strInput << endl;
    }
    
    return 0;
	
    // 当超出范围
    //  这个ofstream析构函数将关闭这个文件
}

这会产生结果:
This is line 1
This is line 2
缓冲输出

可以缓冲C ++中的输出。这意味着输出到文件流的任何内容都可能无法立即写入磁盘。相反,可以对几个输出操作进行批处理和一起处理。这主要是出于性能原因。将缓冲区写入磁盘时,这称为刷新缓冲区。导致缓冲区刷新的一种方法是关闭文件,缓冲区的内容将刷新到磁盘,然后文件将被关闭。

缓冲通常不是问题,但在某些情况下,它可能导致不警惕的并发症。在这种情况下,主要的罪魁祸首是缓冲区中有数据,然后程序立即终止(通过崩溃或通过调用exit())。在这些情况下,不执行文件流类的析构函数,这意味着文件永远不会关闭,这意味着永远不会刷新缓冲区。在这种情况下,缓冲区中的数据不会写入磁盘,并且会永久丢失。这就是为什么在调用exit()之前显式关闭任何打开的文件总是一个好主意。

可以使用ostream :: flush()函数手动刷新缓冲区或将std :: flush发送到输出流。这些方法中的任何一个都可以用于确保缓冲区的内容立即写入磁盘,以防程序崩溃。

一个有趣的注意事项是std :: endl; 还会刷新输出流。因此,过度使用std :: endl(导致不必要的缓冲区刷新)会在执行缓冲I / O时产生性能影响,其中刷新是昂贵的(例如写入文件)。出于这个原因,具有性能意识的程序员通常会使用’\ n’而不是std :: endl在输出流中插入换行符,以避免不必要的缓冲区刷新。

文件模式

如果我们尝试写入已存在的文件会发生什么?再次运行输出示例显示每次运行程序时都会完全覆盖原始文件。相反,如果我们想在文件的末尾添加更多数据呢?事实证明,文件流构造函数采用可选的第二个参数,允许您指定有关如何打开文件的信息。此参数称为模式,它接受的有效标志位于Ios类中。

Ios文件模式 含义
app 以附加模式打开文件
ate 在读/写之前寻找文件的末尾
binary 以二进制模式打开文件(而不是文本模式)
in 以读取模式打开文件(ifstream的默认值)
out 以写入模式打开文件(ofstream的默认值)
trunc 如果文件已存在,则删除该文件

可以通过将它们按位OR运算来指定多个标志(使用|运算符)。Ifstream默认为ios :: in file模式。Ofstream默认为ios :: out文件模式。并且fstream默认为ios :: in | ios :: out文件模式,意味着您可以默认读取和写入。

让我们编写一个程序,将另外两行添加到我们之前创建的Sample.dat文件中:

#include <cstdlib> // for exit()
#include <iostream>
#include <fstream>
 
int main()
{
    using namespace std;
 
    // 我们将通过ios:app标志告诉ofstream追加
    // 而不是重写文件。我们不需要传入ios :: out
    // 因为ofstream默认为ios :: out
    ofstream outf("Sample.dat", ios::app);
 
    // 如果我们无法打开输出文件流进行写入
    if (!outf)
    {
        // 打印错误并退出
        cerr << "Uh oh, Sample.dat could not be opened for writing!" << endl;
        exit(1);
    }
 
    outf << "This is line 3" << endl;
    outf << "This is line 4" << endl;
    
	return 0;
	
    // 当超出范围
    //  这个ofstream析构函数将关闭这个文件
}

现在,如果我们看看Sample.dat(使用上面打印其内容的示例程序之一,或者在文本编辑器中加载它),我们将看到以下内容:

This is line 1
This is line 2
This is line 3
This is line 4
使用open()显式打开文件

就像可以使用close()显式关闭文件流一样,也可以使用open()显式打开文件流。open()的工作方式与文件流构造函数一样,它采用文件名和可选的文件模式。

例如:

ofstream outf("Sample.dat");
outf << "This is line 1" << endl;
outf << "This is line 2" << endl;
outf.close(); // 显式关闭文件
 
// 哎呀,我们忘记了什么
outf.open("Sample.dat", ios::app);
outf << "This is line 3" << endl;
outf.close();
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章