如何使用C++ fstream

534 阅读8分钟

fstream一词是指文件流。流是指从磁盘到C++程序或从C+程序到磁盘的一串字符。将字符从磁盘中的文件移到程序中是输入。从程序中向磁盘中的文件移动字符是输出。输入文件流缩写为ifstream,由模板类basic_ifstream构成。输出文件流缩写为ofstream,由模板类basic_ofstream构成。

输入和输出有可能在一个会话中进行。这是由模板类basic_fstream实现的。现在,fstream是basic_fstream的同义词。fstream,仍然是basic_fstream,使用basic_ifstream和ofstream来操作。

为了在一个会话中单独做输入,单独做输出,或者同时做输入和输出,只需在C++程序中开始使用以下内容(包括流)。

#include
#include .

本教程有四个主要部分:文件流的打开和关闭、输出文件流、追加、输入文件流和编辑文件。编辑文件意味着输入和输出文件流。

文章内容

打开和关闭一个文件流

在打开一个流之前,必须先创建一个流对象。打开一个流意味着在C++程序和磁盘中的文件之间建立一个通道。通过这个通道,字符序列将移动到文件中;或通过这个通道,字符序列将离开文件,来到程序中;或通过这个通道,字符将来回移动。

一个流只为写(输出)、读(输入)或读和写而打开。它也可以因其他原因被打开。

在打开一个流之前,必须构建流对象。最简单的表达方式是在C++ main()函数中如下。

fstream strm。

现在,有了strm对象,就可以使用fstream成员函数open()和close(),在每个函数前面加点运算符。下面的语句可以用来打开一个fstream以供读取。

voidopen("path/to/and/the/file", ios_base::in)。

open()成员函数返回void。

使用流对象时,语句将是

strm.open("path/to/and/the/file", ios_base::in)。

由于open()成员函数返回void,要知道磁盘中的文件是否被成功打开,请使用该成员函数。

bool is_open() const;

如果文件没有打开,它的返回值为0,表示错误;如果文件打开,它的返回值为1,表示正确。

要打开一个文件进行写入,请使用。

strm.open("path/to/and/the/file", ios_base::out)。

"ios_base::in "表示为读而打开,"ios_base::out "表示为写而打开。要打开一个文件进行读写,请使用。

strm.open("path/to/and/the/file", ios_base::in |ios_base::out)。

注意:这里出现了 "ios_base::in | ios_base::out",。

关闭一个流意味着关闭数据在程序和文件之间来回传送的通道。不再有数据可以使用该通道向任何方向发送。关闭流并不意味着关闭流对象。同一个流仍然可以用来打开一个新的通道,该通道在用于传输数据后应被关闭。在打开任何文件流后,要养成关闭它的习惯。当一个流被关闭时,在实际关闭之前,内存中任何本应在文件中的数据都被发送到文件中。关闭fstream的成员函数原型是。

voidclose()。

不幸的是,它返回无效。所以,要知道关闭是否成功,请使用成员函数。

bool is_open() const;

如果关闭成功,这将返回0,意味着流不再是开放的。如果关闭不成功,它将返回1,意味着流不能被关闭。

输出文件流操作

**打开一个文件并给它一个新的内容
**要用fsream打开一个输出流,只需在open()成员函数中单独使用 "ios_base::out"。下面的程序打开了一个文件,并向它发送了一个字符串的内容。

#include
#include
using namespacestd;

int main()
{
fstream strm;
strm.open("dir1/doc1.txt", ios_base::out);
if (strm.is_open () {
charstr[] = "A: This is the first line.\n"
"B: This is the second line.\n"
"C: This is the third line.\n";

strm<< str;

strm.close();
if (strm.is_open()
cout << "Stream could not close!"<<endl;
}
else
cout<<"File could not be opened!"<<endl;

return 0;
}

文件的名称是doc1.txt,位于用户主目录的dir1目录下。该目录dir1应该已经存在。如果doc1.txt不存在,它将被创建。如果它已经存在并且有任何内容,则内容将被替换。

新的内容在程序中用str标识。在程序结束时,字符串内容将被插入到流中,因此,文件中的语句。

strm<<str。

Cout是一个标准输出对象,它通常用于控制台。它使用提取运算符,<<。提取运算符也用于文件流。这里的文件流对象是strm

上面每个引号末尾的'/n'字符是为了确保下一行出现在输出文件的下面。

basic_ostream< charT, traits>&write(constchar_type* s, streamsize n)

可以使用write()成员函数,而不是用插入操作符将文本发送到文件中。

下面的代码说明了这一点。

fstream strm;
strm.open("dir1/temp.txt", ios_base::out);
if (strm.is_open () {
charstr[50] = "Here we are";
strm.write(str, 11);

strm. close();
if (strm. is_open()) .is_open()
cout << "Stream could not close for writing!" <<endl;
}

write()函数的第一个参数是字符阵列的标识符。第二个参数是该数组中的字符数(不含0)。

向文件中添加字符

要将文本追加到一个文件,请单独使用 "ios_base::app",而不是open()成员函数中的 "ios_base::out"。还是要使用插入操作符<<,如下所示。

fstream strm;
strm.open( "dir1/doc1.txt", ios_base::app);
if (strm.is_open () {
charstr[] = "D: This is the fourth line.\n";

strm<< str;

strm.close();
如果 (strm.is_open())
cout << "Stream could not close!" <<endl;
}

现在输出文件应该有四行。

输入文件流操作

**逐个字符读取整个文件
**要用fstream读取一个文件,在open()成员函数中单独使用 "ios_base::in"。下面的程序读取了文件的所有内容并显示在控制台。

#include
#include
using namespacestd;

int main()
{
fstream strm;
strm.open("dir1/doc1.txt", ios_base::in);
if (strm.is_open () {
char c;

while (!strm.eof ()) {
strm.get(c);
cout << c;
}

strm.close();
if (strm.is_open())
cout << "Stream could not close!"<<endl;
}

return 0;
}

eof()是一个成员函数,当到达文件末端时返回1,否则返回0。该程序逐一读取文件中的字符,直到到达文件的末端。它使用get()成员函数,将读取的字符放入已经声明的变量c中。cout将每个字符发送到控制台。

输出的结果应该是。

A:这是第一行。
B:这是第二行。
C:这是第三行。
D:这是第四行。

**用一个函数读取整个文件
**可以用成员函数读取整个文件。

basic_istream< charT, traits>&get(char_type* s, streamsize n, char_type delim) 。

它从文件中复制字符并把它们放入一个字符数组中。它一直这样做,直到遇到分隔符EOF,或者直到它复制了n - 1个字符。它将把NUL('\0')字符作为数组中最后一个连续字符。这意味着为数组选择的字符数应该被估计为至少是文件字符数(包括任何 \n),加上一个NUL字符。它不复制定界符。下面的代码使用这个成员函数复制了doc1.txt的整个文件。

fstream strm;
strm.open("dir1/doc1.txt", ios_base::in);
if (strm.is_open () {
chararr[150];

strm.get(arr,150,EOF);
cout <<arr<<endl;

strm.close();
if (strm.is_open())
cout << "Stream could not close!" <<endl;
}

这里的get()成员函数是上面get()函数的一个重载成员函数。

**逐行阅读
**这里要使用的成员函数是。

basic_istream< charT, traits>&getline(char_type* s, streamsize n, char_type delim)。

它从文件中复制字符并将它们放入一个字符数组。它这样做直到遇到分隔符(如'/n')或复制了n-1个字符。它将把NUL('\0')字符作为数组中最后一个连续字符。这意味着为数组选择的字符数应估计为至少可见的字符数,加上一个空字符。它不复制定界符。下面的代码使用这个成员函数逐行复制doc1.txt的整个文件。

fstream strm;
strm.open("dir1/doc1.txt", ios_base::in);
if (strm.is_open ()) {
chararr[100];

while (!strm.eof ()) {
strm.getline(arr,100,'\n');
cout <<arr<<endl;
}

strm.close();
如果 (strm.is_open())
cout << "Stream could not close!" <<endl;
}

由于复制一行时不复制'\n',所以必须使用endl来显示输出。请注意,数组和streamsize变量中的字符数,已经变得相同了。

如果事先知道定界符是'\n',那么可以使用下面的成员函数。

basic_istream<charT, traits>&getline(char_type* s, streamsize n)。

basic_istream<charT, traits>& seekg(pos_type pos)

包括'/n'在内的字符在文件中都有其自然位置,从0开始,然后是1、2、3,以此类推。seekg(pos)成员函数将指向流对象中某个位置的字符的指针。然后,可以用get(c)来获得该字符。

在当前doc1.txt文件的第27个位置的字符是'B'。下面的代码读取并显示它。

fstream strm;
strm.open("dir1/doc1.txt", ios_base::in);
if (strm.is_open () {
char c;

strm.seekg(27);
strm.get(c);
cout <<c<<endl;

strm.close();
if (strm.is_open())
cout << "Stream could not close!" <<endl;
}

如果给出的位置大于文件中最后一个字符的位置(减去1),则返回null。

pos_type tellg()

当一个文件被读取时,一个内部指针指向下一个要读取的字符。tellg()成员函数可以获得指针所指向的字符的位置号。当文件刚刚打开时,tellg()将返回第一个字符的0。经过一段时间的读取,tellg()会返回一个数字,如上面例子中的27。下面的代码使用告诉()函数,显示了两个位置的数字和它们对应的字符。

fstream strm;
strm.open("dir1/doc1.txt", ios_base::in);
if (strm.is_open () {
char c;

intno=strm.tellg();
strm.seekg(no);
strm.get(c);
cout <<no<< ' ' <<c<<endl;

no= 27;
strm.se ekg(27);
strm.get(c);
cout << no << '< c << endl; strm.<endl;

strm.close();
if (strm.is_open())
cout << "Stream could not close!" <<endl;

输出结果是

0A
27B

用于输出的等效函数是tellp()。

seekdir

seekdir意味着寻求方向。它在ios_base库中定义的常数是:beg代表文件的开始,cur代表文件的当前位置,end代表文件的结束。上述seekkg()函数在输入流中被重载为。

basic_istream& seekg(off_type, ios_base::seekdir)

因此,如果内部指针通过从0开始计数,指向位置27的字符,那么

strm.seekkg(0, ios_base::cur)。

将保持指针在当前位置。

strm.seekkg(5, ios_base::cur)。

将指针向前移动5位,指向doc1.txt文件中第二个 "this "的 "i"。

strm.seekg(-5, ios_base::cur);

将把指针移到后面5位,指向doc1.txt文件第一 "行 "中的 "i"。注意,换行符'\n'的位置被计算在内,它不会在输出端显示。

现在,不管指针可能在哪里。

strm.seekg(0, ios_base::beg)。

取出并保持文件开头的指针;指向文件的第一个字符,偏移量为0,在这种情况下,它将指向 "A"。

strm.seekg(5, ios_base::beg)。

将把指针带到开头,偏移量为5位;指向doc1.txt文件的第一个 "this "中的 "i"。注意,单个空格被算作一个字符。

在 "ios_base::beg "的偏移位置上出现一个负整数是没有用的。

好吧,不管指针可能在哪里。

strm.seekg(0, ios_base::end)。

将采取并维持刚刚在文件结束后的指针;以指向什么都没有。

在 "ios_base::end "的偏移位置上的一个正整数是没有用的。

strm.seekg(-5, ios_base::end)。

将以5个位置的偏移量取到终点;指向doc1.txt文件最后 "一行 "中的 "i"。请注意,'\n'和圆点各算作一个字符。

下面的代码说明了该函数的使用,在当前位置,有一个负的和正的偏移。

fstream strm;
strm.open( "dir1/doc1.txt", ios_base::in);
if (strm.is_open () {
char c;

strm.seekg(27);
strm.seekg(0, ios_base::cur);
strm.get(c);
cout <<c<<endl;

strm.seekg(-5, ios_base::cur);
strm.get(c);
cout <<c<<endl;

strm.seekg(+10, ios_base::cur);
strm.get(c);
cout <<c<<endl;

strm.close();
if (strm.is_open())
cout << "Stream could not close!" <<endl;
}

输出结果是。

B
n
空间

get()成员函数在执行后将指针前移一位。

用于输出的等效函数是。

basic_ostream< charT, traits>&seekp(off_type, ios_base::seekdir)

注意 seekp 中的 "p "代表put,而seekkg中的 "g "代表get。

编辑一个文件

**在C++中的经典文件编辑
**要编辑一个文件,应该打开该文件进行读写,也就是所谓的输入和输出。在经典的方法中,字符被一个一个地读,一个一个地改。文件中的所有字符被读入一个char数组。该数组使用与文件中的位置相对应的字符位置进行修改。之后,数组内容被送回文件,以取代旧内容。这种修改通常是在读取文件时进行的。

要替换一个字符,只需在数组中替换它。要删除一个字符,把前面所有的字符都降到一个地方。要插入一个字符,将所有的字符向前移动一个位置,然后插入。为了完成这个任务,数组的大小应估计为至少是所有最终字符的数量。

为了执行下面的任务,在同一目录下备份文件doc1.txt,将其重命名为doc1Back.txt。在下面的代码示例中,当一个字符被读取时,在编辑之前,它被检查。在代码中,doc1.txt文件第二行的 "B: This",由7个字符组成,被删除。

fstream strm;
chararr[150];
intctr= 0;
strm.open("dir1/doc1.txt", ios_base::in);
if (strm.is_open () {
char c;

intdiff= 7;
bool bl= true;
while (!strm.eof ()) {
strm.get(c);
if (bl== true) {
if (c == 'B' ) {
bl= false;
diff=diff- 1;
如果 (diff== 0)
bl= true;
}
否则 {
arr[ctr] = c;
ctr=ctr+ 1;
}
}
else if (diff> 0 ){
diff=diff- 1;
如果 (diff== 0)
bl= true;
}
}

strm.close();
if (strm.is_open()
cout << "Stream could not close for reading!"<<endl;
}

strm.open("dir1/doc1.txt", ios_base::out);
if (strm. is_open().is_open ()) {

strm.write(arr, ctr-1);

strm. close();
if (strm. is_open()) strm.is_open())
cout << "Stream could not close for writing!" <<endl;
}

新的文件表述是。

A:这是第一行。
是第二行。
C:这是第三行。
D:这是第四行。

下面的代码段在上面的代码中打了两次。

如果 (diff== 0)
bl= true。

为了将doc1.txt文件第二行中由7个字符组成的 "B:这个 "替换为由12个字符组成的 "2:现在,这里",这段代码应该被替换为。

if (diff== 0 ){
bl= true;
for (inti=0;i<12;i++) {
arr[ctr] = repl[i];
ctr=ctr+ 1;
}
}

其中 repl[] 是,

charrepl[] = "2:现在,这里"。

该代码应该在两个地方输入。输出的结果将是。

A:这是第一行。
2:现在,这里是第二行。
C:这是第三行。
D:这是第四行。

结论

fstream类处理从文件到C++程序的输入和从程序到文件的输出。为了使用C++ fstream,必须将该类的一个对象实例化。然后,该流对象必须被打开以进行输入或输出,或同时进行。为了向文件添加文本,必须打开流进行添加。养成习惯,在流被打开和使用后,总是关闭它。如果文件是一个图像文件,那么 "ios_base::binary "将必须使用 | ,与open()成员函数的第二个参数进行OR。这篇文章希望能帮助你使用C++的fstream。