凡是过往,皆为序章

0%

C++文本操作

本篇总结 C++ 的文本操作,即C++文件和流的概念。


文件流

到目前为止,我们使用了iostream标准库,它提供了cin 和 cout 方法分别用于从标准输入读取流和向标准输入写入流

如何从标准输入读取流和向标准输入写入流?这就需要用到 C++ 中另一个标准库fstream,它定义了三个新的数据类型:

数据类型 描述
ofstream 该数据类型表示输出文件流,用于创建文件并向文件写入信息
ifstream 该数据类型表示输入文件流,用于从文件读取信息
fstream 该数据类型通常表示文件流,且同时具有 ofstream 和 ifstream 两种功能,这意味着它可以创建文件,向文件写入信息,从文件读取信息。

要在C++中进行文件处理,必须在 C++ 代码中包含头文件 <iostream><fstream>

打开文件

在从文件读取信息或者向文件写入信息之前,必须先打开文件。ofstreamfstream对象都可以用来打开文件进行操作;如果只需要打开文件进行操作,则使用 ifstream 对象。

下面是open()函数的标准语法。

1
void open(const char *fileName, ios::openmode mode);

在这里,open()成员函数的第一参数指定要打开的文件名字,第二个参数指定打开文件的模式。

模式标志 描述
ios::app 追加模式,所有写入都追加到文件末尾
ios::ate 文件打开后将文件指针位置定位到文件末尾
ios::in 打开文件用于读取
ios::out 打开文件用于写入
ios::trunc 如果该文件已经存在,其内容将在打开之前被截断,即把文件长度设为0.

可以把以上两种或两种以上的模式结合使用,以“或”运算(“|”)的方式。例如:如果想要以写入模式打开文件,并希望截断文件,以防文件已经存在,那么可以使用下面的语法:

1
2
ofstream outFile;
outFile.open( "file.dat", ios::out | ios::trunc );

类似的,如果想要打开一个文件用于读写,可以使用下面的语法:

1
2
ifstream afile;
afile.open("file.dat", ios::out | ios::in)

很多程序中,可能会碰到ofstream out(“Hello.txt”), ifstream in(“…”),fstream foi(“…”)这样的的使用,并没有显式的去调用open()函数就进行文件的操作,直接调用了其默认的打开方式,因为在stream类的构造函数中调用了open()函数,并拥有同样的构造函数,所以在这里可以直接使用流对象进行文件的操作,默认方式如下:

1
2
3
ofstream out("...", ios::out);
ifstream in("...", ios::in);
fstream foi("...", ios::in|ios::out);

关闭文件

使用close() 函数关闭打开的文件,它是 fstream,ifstream 和 ofstream 对象的一个成员。

写入文件

我们使用 流插入运算符( << )向文件写入信息。

读取文件

我们使用 流提取运算符( >> )从文件读取信息。

例子

下面给出一个例子,读取hello.txt文件中的字符串,写入out.txt中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <vector> 
#include <string>
#include <fstream>
#include <iostream>

using namespace std;

int main()
{
ifstream myfile("hello.txt");
ofstream outfile("out.txt", ios::app);
string temp;
if (!myfile.is_open())
{
cout << "未成功打开文件" << endl;
}
while(getline(myfile,temp))
{
outfile << temp;
outfile << endl;
}
myfile.close();
outfile.close();
return 0;
}

其中getline(stream, string)函数的功能:按行从输入流中读入字符,存到string变量

  • 直到出现以下情况为止:

  • 读入了文件结束标志

  • 读到一个新行

  • 达到字符串的最大长度

如果getline()没有读入字符,将返回false,可用于判断文件是否结束。

1
2
3
4
5
6
7
8
9
10
11
12
int v, w, weight;
ifstream infile; //输入流

infile.open("data.txt", ios::in);
if(!infile.is_open ())
cout << "Open file failure" << endl;
while (!infile.eof()) // 到达文件末尾时返回true
{
infile >> v >> w >> weight;
cout << v << "\t" << w << endl;
}
infile.close(); //关闭文件

上述代码的功能是读取data.txt文件的数据,注意,此时要求data.txt文件中的数据是三个一行,每个数据用空格或换行符隔开。

文件指针

文件指针位置在c++中的用法:

标准 描述
ios::beg 文件头
ios::end 文件尾
ios::cur 当前位置

例如:

1
2
3
4
5
file.seekg(0,ios::beg);   //让文件指针定位到文件开头 
file.seekg(0,ios::end); //让文件指针定位到文件末尾
file.seekg(10,ios::cur); //让文件指针从当前位置向文件末方向移动10个字节
file.seekg(-10,ios::cur); //让文件指针从当前位置向文件开始方向移动10个字节
file.seekg(10,ios::beg); //让文件指针定位到离文件开头10个字节的位置

注意:移动的单位是字节,而不是行

状态标志符的验证(Verification of state flags)

除了eof()以外,还有一些验证流的状态的成员函数(所有都返回bool型返回值):

  • bad()

    如果在读写过程中出错,返回 true 。例如:当我们要对一个不是打开为写状态的文件进行写入时,或者我们要写入的设备没有剩余空间的时候。

  • fail()

    除了与bad() 同样的情况下会返回 true 以外,加上格式错误时也返回true ,例如当想要读入一个整数,而获得了一个字母的时候。

  • eof()

    如果读文件到达文件末尾,返回true。

  • good()

    这是最通用的:如果调用以上任何一个函数返回true 的话,此函数返回 false 。

要想重置以上成员函数所检查的状态标志,你可以使用成员函数clear(),没有参数。

string流

string头文件定义了三个类型来支持内存IO,istringstream向string读取数据,ostringstream从string写数据,stringstream既可从string读取数据也可向string写数据,就像string是一个IO流一样。

istringstream的用法

例子如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <string> 
#include <sstream> //使用istringstream所需要的头文件
#include <iostream>
using namespace std;
int main()
{
string str = "Hello world! I am Lee";
istringstream is(str); //将is绑定到str
string s;
while (is >> s)
{
cout << s << endl;
}
return 0;
}

这相当于把一个句子拆分成单词,联系到前文提到的从文件中读取string的方法,如果读取到的string对象为一个句子,包含很多单词,那么我们就可以运用这种方法把string对象拆分开来。

结果:

1
2
3
4
5
Hello
world!
I
am
Lee

ostringstream的用法

​ ostringstream同样是由一个string对象构造而来,ostringstream类向一个string插入字符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <string> 
#include <sstream> //使用ostringstream所需要的头文件
#include <iostream>
using namespace std;
int main()
{
ostringstream ostr;
// ostr.str("abc");//如果构造的时候设置了字符串参数,那么增长操作的时候不会从结尾开始增加,而是修改原有数据,超出的部分增长
ostr.put('d');
ostr.put('e');
ostr<<"fg";
string gstr = ostr.str();
cout<<gstr << endl;
return 0;
}

在上例代码中,我们通过put()或者左移操作符可以不断向ostr插入单个字符或者是字符串,通过str()函数返回增长过后的完整字符串数据,但值 得注意的一点是,当构造的时候对象内已经存在字符串数据的时候,那么增长操作的时候不会从结尾开始增加,而是修改原有数据,超出的部分增长。

~感谢你请我吃糖果~
-------------本文结束,感谢您的阅读,欢迎评论留言!-------------