一.如何写文件
首先给出一段代码,接着再逐行进行解释。第一个程序将建立一个文件,并写入一些字符:
例1.#include<fstream.h>
void main()
{
ofstreamSaveFile(“cpp-home.txt”);
SaveFile <<“Hello World, from www.cpp-home.comand Loobian!”;
SaveFile.close();
}
这个程序将在当前运行目录下建立一个名为cpp-home.txt的文件,并向它写入“HelloWorld, from www.cpp-home.comand Loobian!”。
下面给出各行的含义:
#include <fstream.h>——你需要包含此文件以使用C++的文件输入/输出函数。在这个头文件中声明了若干个类,包括ifstream,ofstream及fstream,它们都继承自istream和ostream类。
ofstreamSaveFile(“cpp-home.txt”);
1)ofstream即“outputfile stream(输出文件流)”。它将建立一个句柄(handle),以便我们以后能以一个文件流的形式写入文件。
2)SaveFile——这是文件句柄的名字,可以换用任何一个名称。
3)(“cpp-home.txt”);——打开名为cpp-home.txt的文件。如果程序运行的当前目录已经存在这样一个文件,则它将被替换掉;万一不存在,程序也会为你创建一个为文件。
当然ofstreamSaveFile(“cpp-home.txt”);
也可以写成
ofstreamSaveFile;//定义一个静态文件输出流对象
SaveFile.open("cpp-home.txt");//打开文件,使文件流与对象建立联系
首先,需要指出的是:ofstream是一个类。因此ofstreamSaveFile(“cpp-home.txt”);这一语句将创建一个该类的对象;而我们在括号中所传递的参数实际上将传给构造函数:在这里我们将我们要建立的文件的名称作为实际参数传递给了该类的构造函数。
SaveFile <<“Hello World, from www.cpp-home.comand Loobian!”;这行语句所做的,是将上面的那段文本写入文件。正如前面所提到的,SaveFile是一个文件句柄,它关联一个打开的流式文件。所以,我们只须输入句柄名,再跟着输入“<<”,然后接着写下一串用引号括起来的文本,就可以实现对文件的写入。如果我们想写入的是某个变量的值而不是带引号的文本,也只须像通常使用cout<< 一样将变量传递给句柄对象,像这样:SaveFile<< variablename;就可以了!
例2.#include<fstream.h>
void main() //程序从这里开始运行
{ int variablename=12345;
ofstreamSaveFile(“cpp-home.txt”);
SaveFile <<variablename;
SaveFile.close();
}
SaveFile.close();——既然我们打开了一个流文件,那么当我们用完它之后,就必须关闭它。SaveFile是ofstream类的一个对象,而该类(ofstream)有一个用于关闭文件的成员函数,即close()函数。因此,我们只要依次输入文件句柄名,点号和close(),就可以关闭该文件!
注意:一旦你关闭文件,在你重新打开它以前,就再不能对它进行访问。
二.读取文件
你已经看到了应该如何写文件。现在,当我们已经得到cpp-home.txt文件时,我们将要读取它,并且将内容打印在屏幕上。
首先给出一段程序代码,然后详细地对它进行解释说明:
例3.#include<fstream.h>
void main()//程序从这里开始
{
ifstreamOpenFile("cpp-home.txt");
char ch;
while(!OpenFile.eof())
{
OpenFile.get(ch);
cout<< ch;
}
cout<<endl;
OpenFile.close();
}
ifstreamOpenFile(“cpp-home.txt”) ,ifstream表示“inputfile stream(输入文件流)”。在前一节的程序中,出现的则是ofstream,它的意义是“outputfilestream(输出文件流)”。前一节的程序是进行文件的写操作,这就是它用“output(输出)”来表示的原因。而本节的程序则是读取一个文件,这就是它用“input(输入)”来表示的原因。OpenFile是ifstream类的一个对象,它将关联一个输入文件流;而用引号括住的内容,就是将要打开的文件的名称。
当然ifstreamOpenFile(“cpp-home.txt”)也可以写成这样的形式:
ifstream OpenFile;//定义一个静态文件输入流对象
OpenFile.open("cpp-home.txt");//打开文件,使文件流与对象建立联系
char ch;—— 声明一个字符数组(arrayof type char)。只是有一点要提醒:这样的数组(arrays)只能存储一个ASCII字符。
while(!OpenFile.eof())—— 如果已经到达文件末尾,eof()函数将返回一个非零值。因此我们所设计的这个循环将一直持续,直至我们的文件操作到达文件末尾。这样我们就可以遍历整个文件,以便对它进行读取。
OpenFile.get(ch);—— OpenFile是类ifstream的一个对象。该类声明了一个名为get()的成员函数。只要我们拥有该对象,我们自然就可以调用这个函数。get()函数从相应的流文件中读出一个字符,并将其返回给变量。在本例中,get()函数只带一个参数——用于存储所读取的字符的变量。所以,调用OpenFile.get(ch)后程序将会从OpenFile流中读取一个字符并存入变量ch中。
注意:如果你再次调用该函数,它将读取下一个字符,而不是原来的那一个!
这就是我们要不断反复循环直至读操作到达文件尾的原因。每循环一次,我们将读出一个字符并将它保存在ch中。
cout << ch; ——显示ch变量值,它保存了读取得到的字符。
File.close();—— 我们打开了一个流式文件,就需要关闭它。使用close()函数即可将它关闭,这和前一节的一样!
注意:一旦你关闭了一个文件,在你重新打开它之前,你不能再对它进行访问。
三.掌握输入/输出流
到目前为止,所展示的只是单一的打开文件的途径:要么为读取而打开,要么为写入而打开。但文件还可以以其它方式打开。例如:
ifstreamOpenFile(“cpp-home.txt”);
正如以前所提到的,以上的代码创建一个类ifstream的对象,并将文件的名字传递给它的构造函数。但实际上,还存在有不少的重载的构造函数,它们可以接受不止一个的参数。同时,还有一个open()函数可以做同样的事情。下面是一个以上代码的示例,但它使用了open()函数:
ifstream OpenFile;
OpenFile.open(“cpp-home.txt”);
它们之间没有什么区别!只不过如果你要创建一个文件句柄但不想立刻给它指定一个文件名,那么你可以使用open()函数过后进行指定。顺便再给出一个要使用open()函数的例子:如果你打开一个文件,然后关闭了它,又打算用同一个文件句柄打开另一个文件,这样一来,你将需要使用open()函数。
考虑以下的代码示例:
例4.#include<fstream.h>
void read(ifstream&T) //pass the file stream to the function
{
//the method to reada file, that I showed you before
charch;
while(!T.eof())
{
T.get(ch);
cout<< ch;
}
cout<< endl << "--------" << endl;
}
void main()
{
ifstreamT("file1.txt");
read(T);
T.close();
T.open("file2.txt");
read(T);
T.close();
}
据此,只要有file1.txt和file2.txt存储了文本内容,你将看到这些内容。
但是,文件名并不是你唯一可以向open()函数或者构造函数(其实都一样)传递的参数。下面是一个函数原型:
ifstreamOpenFile(char *filename, int open_mode);
其中,filename表示文件的名称(一个字符串),而新出现的则是open_mode(打开模式)。open_mode的值用来定义以怎样的方式打开文件。下面是打开模式的列表:
名称 | 描述 |
ios::in | 打开一个输入文件 |
ios::out | 打开一个文件,用于输出 |
ios::app | 打开一个输出文件用于在文件尾添加数据,此方式使用ios::out |
ios::ate | 打开一个现存文件(用于输入和输出)并查找到结尾,此方式不使用ios::out |
ios::trunc | 删除文件原来已存在的内容(清空文件) |
ios::nocreate | 如果要打开的文件并不存在,则打开失败,那么以此参数调用open()函数将无法进行。nocreate的意思是不建立新文件。 |
ios::noreplace | 如果要打开的文件已存在,则打开失败,那么试图用open()函数打开时将返回一个错误。 |
ios::binary | 以二进制的形式打开一个文件(默认是文本模式)。 |
实际上,以上的值都属于一个枚举类型的int常量。下面是一个关于如何使用打开模式的例子:
例5.#include<fstream.h>
void main()
{
ofstreamSaveFile("file1.txt", ios::ate);
SaveFile<< "That's new!\n";
SaveFile.close();
}
正如在表中所看到的那样,使用ios::ate将会从文件的末尾开始执行写入。如果我没有使用它,原来的文件内容将会被重新写入的内容覆盖掉。不过既然我已经使用了它,那么我只会在原文件的末尾进行添加。所以,如果file1.txt原有的内容是这样:
Hi! This is testfrom www.cpp-home.com!
那么执行上面的代码后,程序将会为它添上“That’snew!”,因此它看起来将变成这样:
Hi! This is testfrom www.cpp-home.com!That’s new!
假如你打算设置不止一个的打开模式标志,只须使用OR操作符或者是| ,如
ios::ate|ios::binary
四.写和读取文件
当怎样打开一个可以同时进行读取和写入操作的文件!下面就是实现的方法:
fstreamFile(“cpp-home.txt”,ios::in | ios::out);
实际上,这只是一个声明语句。上面的代码创建了一个名为“File”的流式文件的句柄。它是fstream类的一个对象。当使用fstream时,你应当指定ios::in和ios::out作为文件的打开模式。这样,你就可以同时对文件进行读、写,而无须创建新的文件句柄。当然,我们也可以只进行读或者写的操作。那样的话,相应地应当只使用ios::in或者只使用ios::out。
下面就先给出示例代码:
例6.#include<fstream.h>
void main()
{ fstreamFile("test.txt",ios::in | ios::out);
File<< "Hi!"; //将“Hi!”写入文件
staticchar str[10]; //当使用static时,数组会自动被初始化
//即是被清空为零
File.seekg(ios::beg);// 回到文件首部
// 此函数将在后面解释
File>> str;
cout<< str << endl;
File.close();
}
fstreamFile(“test.txt”, ios::in | ios::out);—— 此行创建一个fstream对象,执行时将会以读/写方式打开test.txt文件。这意味着你可以同时读取文件并写入数据。
File << “Hi!”;——将“Hi!”写入文件
static char str[10];—— 这将创建一个容量为10的字符数组。在创建数组的同时对其进行初始化(全部用0进行初始化)。
File.seekg(ios::beg);//回到文件首部
首先看while(!OpenFile.eof())
{
OpenFile.get(ch);
cout<< ch;}
这是一个while型循环,它会一直反复,直至程序的操作到达文件的尾端。但这个循环如何知道是否已经到了文件末尾?嗯,当你读文件的时候,会有一个类似于“内置指针(inside-pointer)”的东西,它表明你读取(写入也一样)已经到了文件的哪个位置,就像记事本中的光标。而每当你调OpenFile.get(ch)的时候,它会返回当前位置的字符,存储在ch变量中,并将这一内置指针向前移动一个字符。因此下次该函数再被调用时,它将会返回下一个字符。而这一过程将不断反复,直到读取到达文件尾。所以,函数seekg()将把内置指针定位到指定的位置(依你决定)。你可以使用:
ios::beg——可将它移动到文件首端
ios::end——可将它移动到文件末端
同时,必须指出,函数seekg()是被重载的,例如:
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个字节的位置
代码一:
例7.#include<fstream.h>
void main()
{
fstreamFile("test.txt",ios::in | ios::out);
File <<"Hi! Do you know me?"; //将"Hi! Do you know me?"写入文件
static charstr[10]; //当使用static时,数组会自动被初始化
//即是被清空为零
File.seekg(-5,ios::end);//
File >>str;
cout <<str << endl;
File.close();
}
显示结果为:w
代码二:
例8.#include <fstream.h>
void main()
{
fstreamFile("test.txt",ios::in | ios::out);
File <<"Hi! Do you know me?"; //将"Hi! Do you know me?"写入文件
static charstr[10]; //当使用static时,数组会自动被初始化
//即是被清空为零
File.seekg(-4,ios::end);//指向倒数第四个字符
File >>str;
cout <<str << endl;
File.close();
}
显示结果为:me?
综上两个例子,我们可知:seekg()将把内置指针定位到指定的位置时,如果指定的位置为空格所在的位子,则显示该指定位置的后面的字符,如果该指定位置不是空格位,则从该位开始显示字符知道遇到空格位停止(个人理解,未找到相关资料)
所以把“Hi”写进文件之后,内置指针将被设为指向其后面……也就是文件的末尾。因此我必须将内置指针设回文件起始处。这就是这个函数seekg()在此处的确切用途。
File >> str;——此行会从文件中读取一个单词,然后将它存入指定的数组变量中。
例如,如果文件中有这样的文本片断:
Hi! Do you know me?
使用File>> str,则只会将“Hi!”输出到str数组中。你应当已经注意到了,它实际上是将空格作为单词的分隔符进行读取的。
由于存入文件中的只是单独一个“Hi!”,所以不需要写一个while循环,那会花费更多的时间来写代码。这就是使用此方法的原因。到目前为止,所使用的读取文件的while循环中,程序读文件的方式是一个字符一个字符进行读取的。然而你也可以一个单词一个单词地进行读取,像这样:
char str[30]; //每个单词的长度不能超过30个字符
while(!OpenFile.eof())
{
OpenFile>> str;
cout<< str;
}
代码如下:
例9.#include<fstream.h>
void main()
{ fstreamFile("test.txt",ios::in | ios::out);
File <<"Hi! Do you know me?"; //将"Hi!Do you know me?"写入文件
static charstr[10]; //当使用static时,数组会自动被初始化
//即是被清空为零
File.seekg(ios::beg);// 回到文件首部
while(!File.eof())
{
File >>str;
cout <<str;
cout<<endl;
}
File.close();
}
你也可以一行一行地进行读取,像这样:
char line[100]; //每个整行将会陆续被存储在这里
while(!OpenFile.eof())
{
OpenFile.getline(line,100);// 100是数组的大小
cout << line<< endl;
}
代码如下:
例10.#include<iostream>
#include <fstream>
using namespace std;
void main()
{
ifstream ifile("test.txt ");
char line[100]; //每个整行将会陆续被存储在这里
while(!ifile.eof())
{
ifile.getline(line,100);// 100是数组的大小
cout << line<< endl;
}
ifile.close();
}
假设test.txt文件的内容为
Hi! Do you know me?
14.8710373022865490
14.4078392848202680
14.4461924174540820
14.0572268190424620
13.6271417430539470
13.4037407958168820
12.7490292405028750
12.2693965610416470
12.0518395076865090
11.7411374917238780
则显示结果为:
Hi! Do you know me?
14.8710373022865490
14.4078392848202680
14.4461924174540820
14.0572268190424620
13.6271417430539470
13.4037407958168820
12.7490292405028750
12.2693965610416470
12.0518395076865090
11.7411374917238780
你现在可能想知道应当使用哪种方法。建议使用时用逐行读取的方式,或者逐字符读取的方式。而逐词读取的方式并非一个好的方案,因为它不会读出新起一行这样的信息,所以如果文件中新起一行时,它将不会将那些内容新起一行进行显示,而是加在已经打印的文本后面。而使getline()或者get()都将会向你展现出文件的本来面目!
五.检测文件是否成功打开
现在介绍如何检测文件打开操作是否成功。需要注意的是,出现“X”的时候,它实际可以以“o”、“i”来代替,或者也可以什么都不是(那将是一个fstream对象)。
最通常的作法: XfstreamFile(“cpp-home.txt”);
if (!File)
{
cout << “Erroropening the file! Aborting…\n”;
exit(1);
}
如果文件已经被创建,返回一个错误
ofstreamFile("unexisting.txt", ios::nocreate);
if(!File)
{
cout << “Erroropening the file! Aborting…\n”;
exit(1);
}
代码如下:
例11.#include<fstream.h>
#include<iomanip>
void main(){
ofstreamFile("unexisting.txt", ios::nocreate);
if(!File)
{
cout << "Erroropening the file! Aborting…\n";
exit(1);
}
}
使用fail()函数
ofstreamFile("filer.txt", ios::nocreate);
if(File.fail())
{
cout << “Erroropening the file! Aborting…\n”;
exit(1);
}
代码如下:
例12.#include<fstream.h>
#include<iomanip>
void main(){
ofstreamFile("file.txt", ios::nocreate);
if(File.fail())
{
cout << "Erroropening the file! Aborting…\n";
exit(1);
}
}
对于fail()函数,如果有任何输入/输出错误(不是在文件末尾)发生,它将返回非零值。
如果你已经创建一个流文件对象,但你没有进行打开文件操作,像这样:
ifstream File;//也可以是一个ofstream这样,我们就拥有一个文件句柄,但我们仍然没有打开文件。如果你打算迟些打开它,那么可以用open()函数来实现。如果在程序的某处,可能需要知道当前的句柄是否关联了一个已经打开的文件,那么你可以用is_open()来进行检测。如果文件没有打开,它将返回0(false);如果文件已经打开,它将返回1(true)。例如:
ofstream File1;
File1.open("file1.txt");
cout <<File1.is_open() << endl;
代码如下:
例13.#include<fstream.h>
void main(){
ofstream File1;
File1.open("file1.txt");
cout <<File1.is_open() << endl;
}
上面代码将会返回1(译注:指File1.is_open()函数,下句同),因为我们已经打开了一个文件(在第二行)。而下面的代码则会返回0,这是由于我们没有打开文件,而只是创建了一个流文件句柄:
ofstream File1;
cout <<File1.is_open() << endl;
代码如下:
例14.#include<fstream.h>
void main(){
ofstream File1;
cout <<File1.is_open() << endl;
}
六.检测输入/输出的状态标志
C++中负责的输入/输出的系统包括了关于每一个输入/输出操作的结果的记录信息。这些当前的状态信息被包含在io_state类型的对象中。io_state是一个枚举类型(就像open_mode一样),以下便是它包含的值(译注:表中第一列为枚举值的名称,第二列为该值相应含义的描述):
函数 | 功能及返回值 |
goodbit | 无错误 |
Eofbit | 已到达文件尾 |
failbit | 非致命的输入/输出错误 |
badbit | 致命的输入/输出错误 |
clear | 设置内部错误状态,如果是默认参数调用,则清除所有错误位 |
rdstate | 返回当前错误状态 |
有两种方法可以获得输入/输出的状态信息。一种方法是通过调用rdstate()函数,它将返回当前状态的错误标记(上表中提到的)。例如,假如没有任何错误,则rdstate()会返回goodbit.
另一种方法则是使用下面任何一个函数来检测相应的输入/输出状态:
bool bad();
bool eof();//不断读取文件内容直到到达文件末尾!
bool fail();//检测一个打开操作是否成功
bool good();
假如badbit标志被标设(译注:原文为“If the badbit flag is up”,这里将“isup”译为“标设”,意即出现了badbit对应的错误,badbit状态被置为当前的错误状态,下同),则bad()函数返回true;假如failbit标志被标设,则fail()函数返回true;假如没有错误发生(goodbit标志被标设),则good()函数返回true;假如操作已经到达了文件末尾(eofbit被标设),则eof()函数返回true.
如果错误发生,你必须清除这些错误状态,以使你的程序能正确适当地继续运行。要清除错误状态,需使用clear()函数。此函数带一个参数,它是你将要设为当前状态的标志值。假使你想让你的程序运行下去,只要将ios::goodbit作为实参。你将在以下内容中看到示例代码。
示例1:简单的状态检测
// 实际应用中可将FileStream替换成你相应在使用的文件流句柄
if(FileStream.rdstate()== ios::eofbit)
cout<< "End of file!\n";
if(FileStream.rdstate()== ios::badbit)
cout<< "Fatal I/O error!\n";
if(FileStream.rdstate()== ios::failbit)
cout<< "Non-fatal I/O error!\n";
if(FileStream.rdstate()== ios::goodbit)
cout << "Noerrors!\n";
例15.clear()函数
#include <fstream.h>
void main()
{
ofstreamFile1("file2.txt"); //建立file2.txt
File1.close();
//下面的检测代码将会返回错误,这是因为我使用了ios::noreplace打开模式
//它模式在试图打开一个已存在的文件时会返回错误
ofstreamTest("file2.txt",ios::noreplace);
//上一行将导致ios::failbit错误,我们这就将其演示出来
if(Test.rdstate()== ios::failbit)
cout<< "Error...!\n";
Test.clear(ios::goodbit);// 将当前状态重置为ios::goodbit
if(Test.rdstate()== ios::goodbit) // 检测程序是否已经正确地施行了设置
cout<< "Fine!\n";
Test.clear(ios::eofbit);// 将状态标志设为ios::eofbit.无实际用途.
if(Test.rdstate()== ios::eofbit) // 检测是否已经正确地施行了设置 cout<< "EOF!\n";
Test.close();
}
除了使用标记值判断,你也可以使用函数(译注:指bad()、eof()、fail()、good()这些函数)的形式进行判断。两者实际上是一样的——都是检测某个标记是否被标设。
函数 | 功能及返回值 |
bad | 如果出现一个不可恢复的错误,则返回一个非0值 |
fail | 如果出现一个不可恢复的错误或一个预期的条件,则返回一个非0值,在用零参量调用clear后,错误标记被清除 |
good | 如果所有错误标记和文件结束标记都是清除的,则返回一个非0值 |
eof | 遇到文件结尾条件,则返回一个非0值 |
clear | 设置内部错误状态,如果是默认参数调用,则清除所有错误位 |
rdstate | 返回当前错误状态 |
七.二进制文件的处理
虽然有规则格式(formatted)的文本(到目前为止我所讨论的所有文件形式)非常有用,但有时候你需要用到无格式(unformatted)的文件——二进制文件。它们和你的可执行程序看起来一样,而与使用<<及>>操作符创建的文件则大不相同。get()函数与put()函数则赋予你读/写无规则格式文件的能力:要读取一个字节,你可以使用get()函数;要写入一个字节,则使用put()函数。
译注:所谓“规则格式文本(formattedtext)”即我们平时所说的文本格式,而与之相对的“无格式文件(unformattedfiles)”
get()函数与put()都各带一个参数:一个char型变量或一个字符。
假如你要读/写一整块的数据,那么你可以使用read()和write()函数。它们的原型如下:
istream &read(char*buf, streamsize num);
ostream &write(constchar *buf, streamsize num);
对于read()函数,buf应当是一个字符数组,由文件读出的数据将被保存在这儿。对于write()函数,buf是一个字符数组,它用以存放你要写入文件的数据。对于这两个函数,num是一个数字,它指定你要从文件中读取/写入的字节数。
假如在读取数据时,在你读取“num”个字节之前就已经到达了文件的末尾,那么你可以通过调用gcount()函数来了解实际所读出的字节数。此函数会返回最后一次进行的对无格式文件的读入操作所实际读取的字节数。
如果你要以二进制方式对文件进行读/写,那么你应当将ios::binary作为打开模式加入到文件打开的参数表中。
例16.使用get()和put()
#include <fstream.h>
void main()
{
fstreamFile("test_file.txt",ios::out | ios::in | ios::binary);
char ch;
ch='o';
File.put(ch);// 将ch的内容写入文件
File.seekg(ios::beg);//定位至文件首部
File.get(ch);//读出一个字符
cout <<ch << endl; // 将其显示在屏幕上
File.close();
}
显示结果为:o
例17.使用read()和write()
#include <fstream.h>
#include <string.h>
void main()
{
fstreamFile("test_file.txt",ios::out | ios::in | ios::binary);
chararr[13];
strcpy(arr,"HelloWorld!"); //将HelloWorld!存入数组
File.write(arr,5);// 将前5个字符——"Hello"写入文件
File.seekg(ios::beg);// 定位至文件首部
staticchar read_array[10]; // 在此我将打算读出些数据
File.read(read_array,3);// 读出前三个字符——"Hel"
cout <<read_array << endl; // 将它们输出
File.close();
}
显示结果为:Hel
八.一些有用的函数
8.1 tellg()函数
tellg()——返回一个int型数值,它表示“内置指针”的当前位置。此函数仅当你在读取一个文件时有效。例如:
例18.#include<fstream.h>
void main()
{
//假如我们已经在test_file.txt中存有了“Hello”的内容
ifstream File("test_file.txt");
char arr[10];
File.read(arr,10);
//由于Hello占5个字符,因此这里将返回5,如果test_file.txt中的字符个数大于10个,则这里返回10
cout << File.tellg() << endl;
File.close();
}
8.2tellp()函数
tellp()——与tellg()有同样的功能,但它用于写文件时。总而言之:当我们读取一个文件,并要知道内置指针的当前位置时,应该使用tellg();当我们写入一个文件,并要知道内置指针的当前位置时,应该使用tellp().由于此函数的用法与tellg()完全一样,例如:
例19.#include<fstream.h>
void main()
{
ofstreamFile("test_file.txt"); File<<"hello";
cout <<File.tellp() << endl;
File.close();
}
此时的显示结果应该为5。
8.3seekp()函数
seekp() ——还记得seekg()么?在读取一个文件,并想达到文件中某个特定位置时,就曾使用过它。seekp()亦如此,只不过它用于写入一个文件的时候。例如,在进行文件读操作时,而要定位到当前位置的三个字符之前,则需调用FileHandle.seekg(-3).但如果我是在写入一个文件,并且比如我要重写后5个字符的内容,我就必须往回跳转5个字符,因而,我应该使用FileHandle.seekp(-5)
例20.#include<iostream>
#include<fstream>
#include<string>
using namespace std;
int main()
{
ofstreamout("a.txt");
out<<"123456789"<<endl;
out.close();
fstreamifile("a.txt",ios::in|ios::out);
ifile.seekp(3);
char cstr[3]="wu";
ifile.write(cstr,2);
ifile.close();
ifstreamin("a.txt");
string str;
in>>str;
cout<<str<<endl;
return 0;
}
8.4ignore()函数
ignore() ——使用于读取文件之时。如果你想略过一定数量的字符,只需使用此函数。实际上,你也可以使用seekg()来代替,然而使用ignore()有一个优点——你可以指定一个特定“界限规则(delimiterrule)”,同样使得ignore()在指定的位置停下。函数原型如下:
istream&ignore( int nCount,delimiter );
nCount表示要略过的字符数量,而delimiter——与它的名称有着同样的含义:假如你想在文件末尾停下,则可使用EOF值传入,这样一来此函数就等同于seekg();但该参数还可以使用其他值,例如‘\n’这样可以在换行的同时定位在新行处。下面是示例:
例21. #include<fstream.h>
void main()
{
//假设test_file.txt中已经存有"HelloWorld"这一内容
ifstream File("test_file.txt");
static char arr[10];
//假如一直没有遇到字符"l",则向前定位直到跳过6个字符
//而如果期间遇到"l",则停止向前,定位在该处
File.ignore(6,'l'); //改为’\n’,则显示world
File.read(arr,10);
cout <<arr << endl; // 它将显示"loWorld!"
File.close();
}
8.5getline()函数
getline() ——此函数不但可用于逐行读取,而且它还可以设为遇到某个特定字符后停止读取。下面给出传递这一参数的方法:
getline(array_size,delim);
Array表示存储读取的内容
Size表示要存入字符的个数
delim 终结符
以下为示例代码:
例22.#include<fstream.h>
void main()
{
//假设test_file.txt中已经存有"HelloWorld"这一内容
ifstreamFile("test_file.txt");
static char arr[10];
/* 读取,直到满足下面的条件之一
1)已经读取10个字符
2)遇到字母"o”
*/
File.getline(arr,10,'o');
cout << arr <<endl; // 将显示"Hell"
File.close();
}
8.6peek()函数
peek() ——此函数将返回输入流文件的下一个字符,但它不移动内置指针。像get()这样的函数也返回输入流文件的下一个字符,而与此同时它将移动内置指针。所以当你再次调用get()函数的时候,它会返回再下一个字符,而非前面那个。所以,假如你连续两次调用peek()函数,它会返回同一个字符。考虑以下代码:
例23.#include<fstream.h>
void main()
{
//假设test_file.txt中已经存有"HelloWorld"这一内容
ifstream File("test_file.txt");
char ch;
File.get(ch);
cout << ch << endl;
cout<<char(File.peek()) << endl;
cout<<char(File.peek()) << endl;
File.get(ch);
cout <<ch << endl;
File.close();
}
显示结果为:
H
e
e
e
peek()函数实质上返回的是字符的ASCII码,而非字符本身。因此,假如你想看到字符本身,所以得像示例中做的那样进行调用(译注:即要转为char类型)。
8.7_unlink()函数
_unlink() ——删除一个文件。假如你要使用此函数,需要在你的程序中包含io.h头文件。下面是示例代码:
例24. #include<fstream.h>
#include <io.h>
void main()
{
ofstream File;
File.open("delete_test.txt"); //创建一个文件
File.close();
_unlink("delete_test.txt");// 删除这个文件
//试图打开此文件,但假如它已不存在
// 函数将返回一个ios::failbit错误值
File.open("delete_test.txt",ios::nocreate);
// 验证它是否返回该值
if(File.rdstate() == ios::failbit)
cout << "Error...!\n";
File.close();
}
8.8putback()函数
putback()——此函数将返回最后一个所读取字符,同时将内置指针移动-1个字符(前移)。换言之,如果你使用get()来读取一个字符后再使用putback(),它将为你返回同一个字符,然而同时会将内置指针移动-1个字符,所以你再次使用get()时,它还是会为你返回同样的字符。下面是示例代码:
例25.#include<fstream.h>
void main()
{
//test_file.txt应包含内容"HelloWorld"
ifstreamFile("test_file.txt");
char ch;
File.get(ch);
cout << ch << endl; // 将显示"H"
File.putback(ch);
cout << ch << endl; // 仍将显示"H"
File.get(ch);
cout <<ch << endl; // 再一次显示"H"
File.close();
}
代码二:
例26.#include<fstream.h>
void main()
{ //test_file.txt应包含内容"HelloWorld"
ifstreamFile("test_file.txt");
char ch;
File.get(ch);
cout <<ch << endl; // 将显示"H"
cout<<char(File.peek()) << endl;
File.putback(ch);
cout <<ch << endl; // 仍将显示"H"
File.close();
}
显示结果为:H
e
H
8.9 flush()函数
flush() ——在处理输出流文件的时候,你所存入的数据实际上并非立刻写入文件,而是先放入一个缓冲区中,直到该缓冲区放满数据之后,这些数据才被存入真正的文件中(在你的磁盘上)。旋即缓冲区会被清空,再重新进行下一轮写入。
但假如你想在缓冲区写满之前就将其中的数据写入磁盘,则使用flush()函数。只须像这样进行调用:FileHandle.flush(),这样缓冲区内的数据将会写入实际的物理文件,而后缓冲区被清空。