在网上搜集的关于文件读取写入的文章,非原创!

 

freopen以前经常使用,比较方便,可以当作模板,在中间替换为自己的代码即可使用。

#include <stdio.h> // 实际使用中发现freopen也包含在iostream.h中,C++代码#include <iostream.h>即可。

            

int main()

{

     freopen("sample.in", "r", stdin);

     freopen("sample.out", "w", stdout);

            

     /* 同控制台输入输出 */

            

     fclose(stdin);

     fclose(stdout);

 

     return 0;

}

-----转自:http://www.slyar.com/blog/c-freopen-stdin-stdout.html  -------------

当我们求解acm题目时,通常在设计好算法和程序后,要在调试环境(例如VC 等)中运行程序,输入测试数据,当能得到正确运行结果后,才将程序提交到oj中。但由于调试往往不能一次成功,每次运行时,都要重新输入一遍测试数据,对于有大量输入数据的题目,输入数据需要花费大量时间。

        使用freopen函数可以解决测试数据输入问题,避免重复输入,不失为一种简单而有效的解决方法。 

 函数名:freopen
声明:FILE *freopen( const char *path, const char *mode, FILE *stream );
所在文件: stdio.h
参数说明:
path: 文件名,用于存储输入输出的自定义文件名。
mode: 文件打开的模式。和fopen中的模式(如r-只读, w-写)相同。
stream: 一个文件,通常使用标准流文件。
返回值:成功,则返回一个path所指定文件的指针;失败,返回NULL。(一般可以不使用它的返回值)
功能:实现重定向,把预定义的标准流文件定向到由path指定的文件中。标准流文件具体是指stdin、stdout和stderr。其中stdin是标准输入流,默认为键盘;stdout是标准输出流,默认为屏幕;stderr是标准错误流,一般把屏幕设为默认。


        下面以在VC下调试“计算a+b”的程序举例。
C语法:
#include <stdio.h>
int main()
{
int a,b;
freopen("debug\\in.txt","r",stdin); //输入重定向,输入数据将从in.txt文件中读取
freopen("debug\\out.txt","w",stdout); //输出重定向,输出数据将保存在out.txt文件中
while(scanf("%d %d",&a,&b)!=EOF)
printf("%d\n",a+b);
fclose(stdin);//关闭文件
fclose(stdout);//关闭文件
return 0;
}

C++语法
#include <stdio.h>
#include <iostream.h>
int main()
{
int a,b;
freopen("debug\\in.txt","r",stdin); //输入重定向,输入数据将从in.txt文件中读取
freopen("debug\\out.txt","w",stdout); //输出重定向,输出数据将保存在out.txt文件中
while(cin>>a>>b)
cout<<a+b<<endl; // 注意使用endl
fclose(stdin);//关闭文件
fclose(stdout);//关闭文件
return 0;
}
        freopen("debug\\in.txt","r",stdin)的作用就是把标准输入流stdin重定向到debug\\in.txt文件中,这样在用scanf或是用cin输入时便不会从标准输入流读取数据,而是从in.txt文件中获取输入。只要把输入数据事先粘贴到in.txt,调试时就方便多了。
类似的,freopen("debug\\out.txt","w",stdout)的作用就是把stdout重定向到debug\\out.txt文件中,这样输出结果需要打开out.txt文件查看。

        需要说明的是:
        1. 在freopen("debug\\in.txt","r",stdin)中,将输入文件in.txt放在文件夹debug中,文件夹debug是在VC 中建立工程文件时自动生成的调试文件夹。如果改成freopen("in.txt","r",stdin),则in.txt文件将放在所建立的工程文件夹下。in.txt文件也可以放在其他的文件夹下,所在路径写正确即可。
        2. 可以不使用输出重定向,仍然在控制台查看输出。
        3. 程序调试成功后,提交到oj时不要忘记把与重定向有关的语句删除。


C++中的文件输入/输出ios:xx eat Processing(zz)

掌握输入/输出流

 

在这一章里,我会提及一些有用的函数。我将为你演示如何打开一个可以同时进行读、写操作的文件;此外,我还将为你介绍其它打开文件的方法,以及如何判断打开操作是否成功。因此,请接着往下读!

到目前为止,我已为你所展示的只是单一的打开文件的途径:要么为读取而打开,要么为写入而打开。但文件还可以以其它方式打开。迄今,你应当已经认识了下面的方法:

 

ifstream OpenFile(“cpp-home.txt”);

 

噢,这可不是唯一的方法!正如以前所提到的,以上的代码创建一个类ifstream的对象,并将文件的名字传递给它的构造函数。但实际上,还存在有不少的重载的构造函数,它们可以接受不止一个的参数。同时,还有一个open()函数可以做同样的事情。下面是一个以上代码的示例,但它使用了open()函数:

 

ifstream OpenFile;

OpenFile.open(“cpp-home.txt”);

 

你会问:它们之间有什么区别吗?哦,我曾做了不少测试,结论是没有区别!只不过如果你要创建一个文件句柄但不想立刻给它指定一个文件名,那么你可以使用open()函数过后进行指定。顺便再给出一个要使用open()函数的例子:如果你打开一个文件,然后关闭了它,又打算用同一个文件句柄打开另一个文件,这样一来,你将需要使用open()函数。

考虑以下的代码示例:

 

#include <fstream.h>

 

void read(ifstream &T) //pass the file stream to the function

{  

//the method to read a file, that I showed you before

    char ch;

 

    while(!T.eof())

    {

       T.get(ch);

       cout << ch;

    }

   

    cout << endl << "--------" << endl;

}

 

void main()

{

    ifstream T("file1.txt");

    read(T);

    T.close();

 

    T.open("file2.txt");

    read(T);

    T.close();

}

 

据此,只要file1.txt和file2.txt并存储了文本内容,你将看到这些内容。

现在,该向你演示的是,文件名并不是你唯一可以向open()函数或者构造函数(其实都一样)传递的参数。下面是一个函数原型:

 

ifstream OpenFile(char *filename, int open_mode);

 

你应当知道filename表示文件的名称(一个字符串),而新出现的则是open_mode(打开模式)。open_mode的值用来定义以怎样的方式打开文件。下面是打开模式的列表:

名称

描述

ios::in

打开一个可读取文件

ios::out

打开一个可写入文件

ios::app

你写入的所有数据将被追加到文件的末尾,此方式使用ios::out

ios::ate

你写入的所有数据将被追加到文件的末尾,此方式不使用ios::out

ios::trunk

删除文件原来已存在的内容(清空文件)

ios::nocreate

如果要打开的文件并不存在,那么以此参数调用open()函数将无法进行。

ios::noreplace

如果要打开的文件已存在,试图用open()函数打开时将返回一个错误。

ios::binary

以二进制的形式打开一个文件。

 

实际上,以上的值都属于一个枚举类型的int常量。但为了让你的编程生涯不至于太痛苦,你可以像上表所见的那样使用那些名称。

下面是一个关于如何使用打开模式的例子:

 

#include <fstream.h>

 

void main()

{

    ofstream SaveFile("file1.txt", ios::ate);

 

    SaveFile << "That's new!\n";

 

    SaveFile.close();

}

 

正如你在表中所看到的:使用ios::ate将会从文件的末尾开始执行写入。如果我没有使用它,原来的文件内容将会被重新写入的内容覆盖掉。不过既然我已经使用了它,那么我只会在原文件的末尾进行添加。所以,如果file1.txt原有的内容是这样:

Hi! This is test from www.cpp-home.com!

那么执行上面的代码后,程序将会为它添上“That’s new!”,因此它看起来将变成这样:

Hi! This is test from www.cpp-home.com!That’s new!

假如你打算设置不止一个的打开模式标志,只须使用OR操作符或者是 | ,像这样:

 

ios::ate | ios::binary

 

我希望现在你已经明白“打开模式”是什么意思了!

现在,是时候向你展示一些真正有用的东西了!我敢打赌你现在还不知道应当怎样打开一个可以同时进行读取和写入操作的文件!下面就是实现的方法:

 

fstream File(“cpp-home.txt”,ios::in | ios::out);

 

实际上,这只是一个声明语句。我将在下面数行之后给你一个代码示例。但此时我首先想提及一些你应当知道的内容。

上面的代码创建了一个名为“File”的流式文件的句柄。如你所知,它是fstream类的一个对象。当使用fstream时,你应当指定ios::in和ios::out作为文件的打开模式。这样,你就可以同时对文件进行读、写,而无须创建新的文件句柄。噢,当然,你也可以只进行读或者写的操作。那样的话,相应地你应当只使用ios::in或者只使用ios::out —— 要思考的问题是:如果你打算这么做,为什么你不分别用ifstream及ofstream来实现呢?

下面就先给出示例代码:

 

#include <fstream.h>

 

void main()
{

    fstream File("test.txt",ios::in | ios::out);

 

    File << "Hi!"; //将“Hi!”写入文件 

    static char str[10]; //当使用static时,数组会自动被初始化

                //即是被清空为零



    File.seekg(ios::beg); // 回到文件首部

                  // 此函数将在后面解释

    File >> str;

    cout << str << endl;

 

    File.close();
}

 

OK,这儿又有一些新东西,所以我将逐行进行解释:

 

fstream File(“test.txt”, ios::in | ios::out); —— 此行创建一个fstream对象,执行时将会以读/写方式打开test.txt文件。这意味着你可以同时读取文件并写入数据。

 

File << “Hi!”; —— 我打赌你已经知道它的意思了。

 

static char str[10]; —— 这将创建一个容量为10的字符数组。我猜static对你而言或者有些陌生,如果这样就忽略它。这只不过会在创建数组的同时对其进行初始化。

 

File.seekg(ios::beg); —— OK,我要让你明白它究竟会做些什么,因此我将以一些有点儿离题、但挺重要的内容开始我的解释。

还记得它么:

 

while(!OpenFile.eof())

    {

       OpenFile.get(ch);

       cout << ch;

    }

 

你是不是曾经很想知道那背后真正执行了什么操作?不管是或不是,我都将为你解释。这是一个while型循环,它会一直反复,直至程序的操作到达文件的尾端。但这个循环如何知道是否已经到了文件末尾?嗯,当你读文件的时候,会有一个类似于“内置指针(inside-pointer)”的东西,它表明你读取(写入也一样)已经到了文件的哪个位置,就像记事本中的光标。而每当你调用OpenFile.get(ch)的时候,它会返回当前位置的字符,存储在ch变量中,并将这一内置指针向前移动一个字符。因此下次该函数再被调用时,它将会返回下一个字符。而这一过程将不断反复,直到读取到达文件尾。所以,让我们回到那行代码:函数seekg()将把内置指针定位到指定的位置(依你决定)。你可以使用:

 

ios::beg —— 可将它移动到文件首端

ios::end —— 可将它移动到文件末端

 

或者,你可以设定向前或向后跳转的字符数。例如,如果你要向定位到当前位置的5个字符以前,你应当写:

File.seekg(-5);

如果你想向后跳过40个字符,则应当写:

File.seekg(40);

同时,我必须指出,函数seekg()是被重载的,它也可以带两个参数。另一个版本是这样子的:

File.seekg(-5,ios::end);

在这个例子中,你将能够读到文件文本的最后4个字符,因为:

1)你先到达了末尾(ios::end)

2)你接着到达了末尾的前五个字符的位置(-5)

为什么你会读到4个字符而不是5个?噢,只须把最后一个看成是“丢掉了”,因为文件最末端的“东西”既不是字符也不是空白符,那只是一个位置(译注:或许ios::end所“指”的根本已经超出了文件本身的范围,确切的说它是指向文件最后一个字符的下一个位置,有点类似STL中的各个容器的end迭代点是指向最后一个元素的下一位置。这样设计可能是便于在循环中实现遍历)。

你现在可能想知道为什么我要使用到这个函数。呃,当我把“Hi”写进文件之后,内置指针将被设为指向其后面……也就是文件的末尾。因此我必须将内置指针设回文件起始处。这就是这个函数在此处的确切用途。

File >> str; —— 这也是新鲜的玩意儿!噢,我确信这行代码让你想起了cin >> .实际上,它们之间有着相当的关联。此行会从文件中读取一个单词,然后将它存入指定的数组变量中。

例如,如果文件中有这样的文本片断:

Hi! Do you know me?

使用File >> str,则只会将“Hi!”输出到str数组中。你应当已经注意到了,它实际上是将空格作为单词的分隔符进行读取的。

由于我存入文件中的只是单独一个“Hi!”,我不需要写一个while循环,那会花费更多的时间来写代码。这就是我使用此方法的原因。顺便说一下,到目前为止,我所使用的读取文件的while循环中,程序读文件的方式是一个字符一个字符进行读取的。然而你也可以一个单词一个单词地进行读取,像这样:

 

char str[30]; // 每个单词的长度不能超过30个字符

while(!OpenFile.eof())

    {

       OpenFile >> str;

       cout << str;

    }

 

你也可以一行一行地进行读取,像这样:

 

char line[100]; // 每个整行将会陆续被存储在这里
while(!OpenFile.eof())
{

OpenFile.getline(line,100); // 100是数组的大小

cout << line << endl;
}

 

你现在可能想知道应当使用哪种方法。嗯,我建议你使用逐行读取的方式,或者是最初我提及的逐字符读取的方式。而逐词读取的方式并非一个好的方案,因为它不会读出新起一行这样的信息,所以如果你的文件中新起一行时,它将不会将那些内容新起一行进行显示,而是加在已经打印的文本后面。而使用getline()或者get()都将会向你展现出文件的本来面目!

现在,我将向你介绍如何检测文件打开操作是否成功。实现上,好的方法少之又少,我将都会涉及它们。需要注意的是,出现“X”的时候,它实际可以以“o”、 “i”来代替,或者也可以什么都不是(那将是一个fstream对象)。

例1:最通常的作法

 

Xfstream File(“cpp-home.txt”);

if (!File)
{

cout << “Error opening the file! Aborting…\n”;

exit(1);
}

 

 

例2:如果文件已经被创建,返回一个错误

 

ofstream File("unexisting.txt", ios::nocreate);

 

if(!File)

{

cout << “Error opening the file! Aborting…\n”;

exit(1);

}

 

例3:使用fail()函数

 

ofstream File("filer.txt", ios::nocreate);

 

if(File.fail())

{

cout << “Error opening the file! Aborting…\n”;

exit(1);

}

 

例3中的新出现的东西,是fail()函数。如果有任何输入/输出错误(不是在文件末尾)发生,它将返回非零值。

我也要讲一些我认为非常重要的内容!例如,如果你已经创建一个流文件对象,但你没有进行打开文件操作,像这样:

 

ifstream File; //也可以是一个ofstream

 

这样,我们就拥有一个文件句柄,但我们仍然没有打开文件。如果你打算迟些打开它,那么可以用open()函数来实现,我已经在本教程中将它介绍了。但如果在你的程序的某处,你可能需要知道当前的句柄是否关联了一个已经打开的文件,那么你可以用is_open()来进行检测。如果文件没有打开,它将返回0 (false);如果文件已经打开,它将返回1 (true)。例如:

 

ofstream File1;

File1.open("file1.txt");

cout << File1.is_open() << endl;

 

上面的代码将会返回1(译注:指File1.is_open()函数,下句同),因为我们已经打开了一个文件(在第二行)。而下面的代码则会返回0,这是由于我们没有打开文件,而只是创建了一个流文件句柄:

ofstream File1;

cout << File1.is_open() << endl;

好啦,这一章讲得够多啦。


C++中的文件输入/输出

(1):你的第一个程序简介
本教程将以C++最基本的文件I/O(输出/输出)开始。此后,我将从更深入的方面,为你展示一些技巧,并分析给出一些有用的函数。
你需要对C++有一个较好的理解,否则这个教程于你而言将是陌生而毫无用处。
你的第一个程序
首先我将给出一段代码,接着再逐行进行解释。我们的第一个程序将建立一个文件,并写入一些字符:
#include <fstream.h>
void main() // 程序从这里开始运行
{
ofstream SaveFile("cpp-home.txt");
SaveFile << "Hello World, from www.cpp-home.com and Loobian!";
SaveFile.close();
}
仅仅如此吗?没错!这个程序将在当前运行目录下建立一个名为cpp-home.txt的文件,并向它写入"Hello World, from www.cpp-home.com and Loobian!"。
下面给出各行的含义:
#include <fstream.h> —— 你需要包含此文件以使用C++的文件输入/输出函数。注意:一旦包含了这个文件,你不再需要(为了使用cout/cin)包含iostream.h,因为fstream.h已经自动包含了它。
在这个头文件中声明了若干个类,包括ifstream,ofstream及fstream,它们都继承自istream和ostream类。
ofstream SaveFile("cpp-home.txt");
1)ofstream即"output file stream(输出文件流)"。它将建立一个句柄(handle),以便我们以后能以一个文件流的形式写入文件。
2)SaveFile —— 这是文件句柄的名字,当然,你还可以换用任何一个你想要的名称。
3)("cpp-home.txt"); —— 打开名为cpp-home.txt的文件。如果程序运行的当前目录已经存在这样一个文件,则它将被替换掉;万一不存在,程序也会为你创建一个为文件,你不必为此而担心。
现在,让我们稍微深入一点点。首先,我要指出的是:ofstream是一个类。因此ofstream SaveFile("cpp-home.txt");这一语句将创建一个该类的对象;而我们在括号中所传递的参数实际上将传给构造函数:在这里我们将我们要建立的文件的名称作为实际参数传递给了该类的构造函数。当然,我们还可以传递其它的一些信息,不过我以后再对其进行讲解。
SaveFile << "Hello World, from www.cpp-home.com and Loobian!"; —— "<<"看起来是不是很亲切?不错,想必你已经在cout << 中见到过。这是一个预定义好的运算符。不管怎么说,这行语句所做的,是将上面的那段文本写入文件。正如前面所提到的,SaveFile是一个文件句柄,它关联一个打开的流式文件。所以,我们只须输入句柄名,再跟着输入"<<",然后接着写下一串用引号括起来的文本,就可以实现对文件的写入。如果我们想写入的是某个变量的值而不是带引号的文本,也只须像通常使用cout << 一样将变量传递给句柄对象,像这样:
SaveFile << variablename;
就可以了!
SaveFile.close(); —— 既然我们打开了一个流文件,那么当我们用完它之后,就必须关闭它。SaveFile是ofstream类的一个对象,而该类(ofstream)有一个用于关闭文件的成员函数,即close() 函数。因此,我们只要依次输入文件句柄名,点号和close(),就可以关闭该文件!
注意:一旦你关闭文件,在你重新打开它以前,就再不能对它进行访问。
以上就是一个可以写文件的最简单程序。的确很容易!不过,正如你即将在以后部分的教程中所看到的,还有更多的东西要学呢
(2):读取文件
(3):掌握输入/输出流(2):读取文件
读取文件
你已经看到了应该如何写文件。现在,当我们已经得到cpp-home.txt文件时,我们将要读取它,并且将内容打印在屏幕上。
首先,我要指出的是,有很多种方法可以读取文件。以后我会向你们介绍所有的方法(就我所知的)。此刻,我先向你展示最佳的方法(我认为的)。
正如你已经熟悉的——我将首先给出一段程序代码,然后,我会详细地对它进行解释说明:
#include <fstream.h>
void main() //程序从这里开始
{
  ifstream OpenFile("cpp-home.txt");
  char ch;
  while(!OpenFile.eof())
  {
    OpenFile.get(ch);
    cout << ch;
  }
  OpenFile.close();
}
你想必已经了解首行的意义所在,而剩下的部分将由我为你解释。
ifstream OpenFile("cpp-home.txt") —— 我猜它对现在的你而言多少会熟悉些!ifstream表示"input file stream(输入文件流)"。在前一节的程序中,出现的则是ofstream,它的意义是"output file stream(输出文件流)"。前一节的程序是进行文件的写操作,这就是它用"output(输出)"来表示的原因。而本节的程序则是读取一个文件,这就是它用"input(输入)"来表示的原因。这一行剩下的代码于你而言应当是熟悉的了:OpenFile是ifstream类的一个对象,它将关联一个输入文件流;而用引号括住的内容,就是将要打开的文件的名称。
请注意:这里没有对要打开的文件是否存在进行测试!以后我将向你指出如何进行检测。
char ch; —— 声明一个字符数组(array of 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()函数即可将它关闭,这和前一节的一样!

注意:一旦你关闭了一个文件,在你重新打开它之前,你不能再对它进行访问。
大功告成了!我希望你能明白我的解释。当你编译并运行这个程序的时候,它应当会输出:
"Hello World, from www.cpp-home.com and Loobian!"
(3):掌握输入/输出流
掌握输入/输出流
在这一章里,我会提及一些有用的函数。我将为你演示如何打开一个可以同时进行读、写操作的文件;此外,我还将为你介绍其它打开文件的方法,以及如何判断打开操作是否成功。因此,请接着往下读!
到目前为止,我已为你所展示的只是单一的打开文件的途径:要么为读取而打开,要么为写入而打开。但文件还可以以其它方式打开。迄今,你应当已经认识了下面的方法:
ifstream OpenFile("cpp-home.txt");
噢,这可不是唯一的方法!正如以前所提到的,以上的代码创建一个类ifstream的对象,并将文件的名字传递给它的构造函数。但实际上,还存在有不少的重载的构造函数,它们可以接受不止一个的参数。同时,还有一个open()函数可以做同样的事情。下面是一个以上代码的示例,但它使用了open ()函数:
ifstream OpenFile;
OpenFile.open("cpp-home.txt");
你会问:它们之间有什么区别吗?哦,我曾做了不少测试,结论是没有区别!只不过如果你要创建一个文件句柄但不想立刻给它指定一个文件名,那么你可以使用open()函数过后进行指定。顺便再给出一个要使用open()函数的例子:如果你打开一个文件,然后关闭了它,又打算用同一个文件句柄打开另一个文件,这样一来,你将需要使用open()函数。
考虑以下的代码示例:
#include <fstream.h> void read(ifstream &T) //pass the file stream to the function

//the method to read a file, that I showed you before
  char ch;
  while(!T.eof())
  {
    T.get(ch);
    cout << ch;
  }
  cout << endl << "--------" << endl;
}
void main()
{
  ifstream T("file1.txt");
  read(T);
  T.close();
  T.open("file2.txt");
  read(T);
  T.close();
}
据此,只要file1.txt和file2.txt并存储了文本内容,你将看到这些内容。
现在,该向你演示的是,文件名并不是你唯一可以向open()函数或者构造函数(其实都一样)传递的参数。下面是一个函数原型:
ifstream OpenFile(char *filename, int open_mode);
你应当知道filename表示文件的名称(一个字符串),而新出现的则是open_mode(打开模式)。open_mode的值用来定义以怎样的方式打开文件。下面是打开模式的列表:
名称     描述
ios::in     打开一个可读取文件
ios::out    打开一个可写入文件
ios::app   你写入的所有数据将被追加到文件的末尾,此方式使用ios::out
ios::ate   你写入的所有数据将被追加到文件的末尾,此方式不使用ios::out ios::trunk  删除文件原来已存在的内容(清空文件)
ios::nocreate 如果要打开的文件并不存在,那么以此参数调用open()函数将无法进行。
ios::noreplace 如果要打开的文件已存在,试图用open()函数打开时将返回一个错误。
ios::binary  以二进制的形式打开一个文件。
实际上,以上的值都属于一个枚举类型的int常量。但为了让你的编程生涯不至于太痛苦,你可以像上表所见的那样使用那些名称。
下面是一个关于如何使用打开模式的例子:
#include <fstream.h>
void main()
{
  ofstream SaveFile("file1.txt", ios::ate);
  SaveFile << "That's new!/n";
  SaveFile.close();
}
正如你在表中所看到的:使用ios::ate将会从文件的末尾开始执行写入。如果我没有使用它,原来的文件内容将会被重新写入的内容覆盖掉。不过既然我已经使用了它,那么我只会在原文件的末尾进行添加。所以,如果file1.txt原有的内容是这样:
Hi! This is test from www.cpp-home.com!
那么执行上面的代码后,程序将会为它添上"That's new!",因此它看起来将变成这样:
Hi! This is test from www.cpp-home.com!That's new!
假如你打算设置不止一个的打开模式标志,只须使用OR操作符或者是 | ,像这样:
ios::ate | ios::binary
我希望现在你已经明白"打开模式"是什么意思了!
现在,是时候向你展示一些真正有用的东西了!我敢打赌你现在还不知道应当怎样打开一个可以同时进行读取和写入操作的文件!下面就是实现的方法:
fstream File("cpp-home.txt",ios::in | ios::out);
实际上,这只是一个声明语句。我将在下面数行之后给你一个代码示例。但此时我首先想提及一些你应当知道的内容。
上面的代码创建了一个名为"File"的流式文件的句柄。如你所知,它是fstream类的一个对象。当使用fstream时,你应当指定 ios::in和ios::out作为文件的打开模式。这样,你就可以同时对文件进行读、写,而无须创建新的文件句柄。噢,当然,你也可以只进行读或者写的操作。那样的话,相应地你应当只使用ios::in或者只使用ios::out —— 要思考的问题是:如果你打算这么做,为什么你不分别用ifstream及ofstream来实现呢?
下面就先给出示例代码:
#include <fstream.h>
void main()
{
  fstream File("test.txt",ios::in | ios::out);
  File << "Hi!"; //将"Hi!"写入文件  
  static char str[10]; //当使用static时,数组会自动被初始化
        //即是被清空为零
  File.seekg(ios::beg); // 回到文件首部
         // 此函数将在后面解释
  File >> str;
  cout << str << endl;
  File.close();
}
OK,这儿又有一些新东西,所以我将逐行进行解释:
fstream File("test.txt", ios::in | ios::out); —— 此行创建一个fstream对象,执行时将会以读/写方式打开test.txt文件。这意味着你可以同时读取文件并写入数据。
File << "Hi!"; —— 我打赌你已经知道它的意思了。
static char str[10]; —— 这将创建一个容量为10的字符数组。我猜static对你而言或者有些陌生,如果这样就忽略它。这只不过会在创建数组的同时对其进行初始化。
File.seekg(ios::beg); —— OK,我要让你明白它究竟会做些什么,因此我将以一些有点儿离题、但挺重要的内容开始我的解释。
还记得它么:
while(!OpenFile.eof())
  {
    OpenFile.get(ch);
    cout << ch;
  }
你是不是曾经很想知道那背后真正执行了什么操作?不管是或不是,我都将为你解释。这是一个while型循环,它会一直反复,直至程序的操作到达文件的尾端。但这个循环如何知道是否已经到了文件末尾?嗯,当你读文件的时候,会有一个类似于"内置指针(inside-pointer)"的东西,它表明你读取(写入也一样)已经到了文件的哪个位置,就像记事本中的光标。而每当你调用OpenFile.get(ch)的时候,它会返回当前位置的字符,存储在ch变量中,并将这一内置指针向前移动一个字符。因此下次该函数再被调用时,它将会返回下一个字符。而这一过程将不断反复,直到读取到达文件尾。所以,让我们回到那行代码:函数seekg()将把内置指针定位到指定的位置(依你决定)。你可以使用:
ios::beg —— 可将它移动到文件首端
ios::end —— 可将它移动到文件末端
或者,你可以设定向前或向后跳转的字符数。例如,如果你要向定位到当前位置的5个字符以前,你应当写:
File.seekg(-5);
如果你想向后跳过40个字符,则应当写:
File.seekg(40);
同时,我必须指出,函数seekg()是被重载的,它也可以带两个参数。另一个版本是这样子的:
File.seekg(-5,ios::end);
在这个例子中,你将能够读到文件文本的最后4个字符,因为:
1)你先到达了末尾(ios::end)
2)你接着到达了末尾的前五个字符的位置(-5)
为什么你会读到4个字符而不是5个?噢,只须把最后一个看成是"丢掉了",因为文件最末端的"东西"既不是字符也不是空白符,那只是一个位置(译注:或许ios::end所"指"的根本已经超出了文件本身的范围,确切的说它是指向文件最后一个字符的下一个位置,有点类似STL中的各个容器的end 迭代点是指向最后一个元素的下一位置。这样设计可能是便于在循环中实现遍历)。
你现在可能想知道为什么我要使用到这个函数。呃,当我把"Hi"写进文件之后,内置指针将被设为指向其后面......也就是文件的末尾。因此我必须将内置指针设回文件起始处。这就是这个函数在此处的确切用途。
File >> str; —— 这也是新鲜的玩意儿!噢,我确信这行代码让你想起了cin >> .实际上,它们之间有着相当的关联。此行会从文件中读取一个单词,然后将它存入指定的数组变量中。
例如,如果文件中有这样的文本片断:
Hi! Do you know me?
使用File >> str,则只会将"Hi!"输出到str数组中。你应当已经注意到了,它实际上是将空格作为单词的分隔符进行读取的。
由于我存入文件中的只是单独一个"Hi!",我不需要写一个while循环,那会花费更多的时间来写代码。这就是我使用此方法的原因。顺便说一下,到目前为止,我所使用的读取文件的while循环中,程序读文件的方式是一个字符一个字符进行读取的。然而你也可以一个单词一个单词地进行读取,像这样:
char str[30]; // 每个单词的长度不能超过30个字符
while(!OpenFile.eof())
  {
    OpenFile >> str;
    cout << str;
  }
你也可以一行一行地进行读取,像这样:
char line[100]; // 每个整行将会陆续被存储在这里
while(!OpenFile.eof())
{
OpenFile.getline(line,100); // 100是数组的大小
cout << line << endl;
}
你现在可能想知道应当使用哪种方法。嗯,我建议你使用逐行读取的方式,或者是最初我提及的逐字符读取的方式。而逐词读取的方式并非一个好的方案,因为它不会读出新起一行这样的信息,所以如果你的文件中新起一行时,它将不会将那些内容新起一行进行显示,而是加在已经打印的文本后面。而使用 getline()或者get()都将会向你展现出文件的本来面目!
现在,我将向你介绍如何检测文件打开操作是否成功。实现上,好的方法少之又少,我将都会涉及它们。需要注意的是,出现"X"的时候,它实际可以以"o"、 "i"来代替,或者也可以什么都不是(那将是一个fstream对象)。
例1:最通常的作法
Xfstream File("cpp-home.txt");
if (!File)
{
cout << "Error opening the file! Aborting.../n";
exit(1);
}
例2:如果文件已经被创建,返回一个错误
ofstream File("unexisting.txt", ios::nocreate);
if(!File)
{
cout << "Error opening the file! Aborting.../n";
exit(1);
}
例3:使用fail()函数
ofstream File("filer.txt", ios::nocreate);
if(File.fail())
{
cout << "Error opening the file! Aborting.../n";
exit(1);
}
例3中的新出现的东西,是fail()函数。如果有任何输入/输出错误(不是在文件末尾)发生,它将返回非零值。
我也要讲一些我认为非常重要的内容!例如,如果你已经创建一个流文件对象,但你没有进行打开文件操作,像这样:
ifstream File; //也可以是一个ofstream
这样,我们就拥有一个文件句柄,但我们仍然没有打开文件。如果你打算迟些打开它,那么可以用open()函数来实现,我已经在本教程中将它介绍了。但如果在你的程序的某处,你可能需要知道当前的句柄是否关联了一个已经打开的文件,那么你可以用is_open()来进行检测。如果文件没有打开,它将返回0 (false);如果文件已经打开,它将返回1 (true)。例如:
ofstream File1;
File1.open("file1.txt");
cout << File1.is_open() << endl;
上面的代码将会返回1(译注:指File1.is_open()函数,下句同),因为我们已经打开了一个文件(在第二行)。而下面的代码则会返回0,这是由于我们没有打开文件,而只是创建了一个流文件句柄:
ofstream File1;
cout << File1.is_open() << endl;

好啦,这一章讲得够多啦。
(5):二进制文件的处理
二进制文件的处理
虽然有规则格式(formatted)的文本(到目前为止我所讨论的所有文件形式)非常有用,但有时候你需要用到无格式(unformatted)的文件——二进制文件。它们和你的可执行程序看起来一样,而与使用<<及>>操作符创建的文件则大不相同。get()函数与put()函数则赋予你读/写无规则格式文件的能力:要读取一个字节,你可以使用get()函数;要写入一个字节,则使用put ()函数。你应当回想起get()——我曾经使用过它。你可能会疑惑为什么当时我们使用它时,输出到屏幕的文件内容看起来是文本格式的?嗯,我猜这是因为我此前使用了<<及>>操作符。
译注:作者的所谓"规则格式文本(formatted text)"即我们平时所说的文本格式,而与之相对的"无格式文件(unformatted files)"即以存储各类数据或可执行代码的非文本格式文件。通常后者需要读入内存,在二进制层次进行解析,而前者则可以直接由预定好的< <及>>操作符进行读入/写出(当然,对后者也可以通过恰当地重载<<及>>操作符实现同样的功能,但这已经不是本系列的讨论范围了)。
get()函数与都各带一个参数:一个char型变量(译注:指get()函数)或一个字符(译注:指put()函数,当然此字符也可以以char型变量提供)。
假如你要读/写一整块的数据,那么你可以使用read()和write()函数。它们的原型如下:
istream &read(char *buf, streamsize num);
ostream &write(const char *buf, streamsize num);
对于read()函数,buf应当是一个字符数组,由文件读出的数据将被保存在这儿。对于write()函数,buf是一个字符数组,它用以存放你要写入文件的数据。对于这两个函数,num是一个数字,它指定你要从文件中读取/写入的字节数。
假如在读取数据时,在你读取"num"个字节之前就已经到达了文件的末尾,那么你可以通过调用gcount()函数来了解实际所读出的字节数。此函数会返回最后一次进行的对无格式文件的读入操作所实际读取的字节数。
在给出示例代码之前,我要补充的是,如果你要以二进制方式对文件进行读/写,那么你应当将ios::binary作为打开模式加入到文件打开的参数表中。
现在就让我向你展示示例代码,你会看到它是如何运作的。
示例1:使用get( )和put( )
#include <fstream.h>
void main()
{
 fstream File("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();
}
示例2:使用read( )和write( )
#include <fstream.h>
#include <string.h>
void main()
{
fstream File("test_file.txt",ios::out | ios::in | ios::binary);
char arr[13];
strcpy(arr,"Hello World!"); //将Hello World!存入数组
File.write(arr,5); // 将前5个字符——"Hello"写入文件
File.seekg(ios::beg); // 定位至文件首部
static char read_array[10]; // 在此我将打算读出些数据
File.read(read_array,3); // 读出前三个字符——"Hel"
 cout << read_array << endl; // 将它们输出 
File.close();
}
(6):一些有用的函数
tellg() ——返回一个int型数值,它表示"内置指针"的当前位置。此函数仅当你在读取一个文件时有效。例如:
  #include <fstream.h>
 void main()
  {
    // 假如我们已经在test_file.txt中存有了"Hello"的内容
  ifstream File("test_file.txt");
  char arr[10];
  File.read(arr,10);
  // 由于Hello占5个字符,因此这里将返回5
    cout << File.tellg() << endl;
   File.close();
  }
 tellp() —— 与tellg()有同样的功能,但它用于写文件时。总而言之:当我们读取一个文件,并要知道内置指针的当前位置时,应该使用tellg();当我们写入一个文件,并要知道内置指针的当前位置时,应该使用tellp(). 由于此函数的用法与tellg()完全一样,我就不给出示例代码了。
 seekp() —— 还记得seekg()么?当我在读取一个文件,并想到达文件中某个特定位置时,就曾使用过它。seekp()亦如此,只不过它用于写入一个文件的时候。例如,假如我在进行文件读写,而要定位到当前位置的三个字符之前,则需调用FileHandle.seekg(-3). 但如果我是在写入一个文件,并且比如我要重写后5个字符的内容,我就必须往回跳转5个字符,因而,我应该使用FileHandle.seekp(-5) .
ignore() —— 使用于读取文件之时。如果你想略过一定数量的字符,只需使用此函数。实际上,你也可以使用seekg()来代替,然而使用ignore()有一个优点—— 你可以指定一个特定"界限规则(delimiter rule)",同样使得ignore()在指定的位置停下。函数原型如下:
   istream& ignore( int nCount, delimiter );
nCount表示要略过的字符数量,而delimiter —— 与它的名称有着同样的含义:假如你想在文件末尾停下,则可使用EOF值传入,这样一来此函数就等同于seekg();但该参数还可以使用其他值,例如'/ n'这样可以在换行的同时定位在新行处。下面是示例:
  #include <fstream.h>
void main()
  {
    // 假设test_file.txt中已经存有"Hello World"这一内容
    ifstream File("test_file.txt");
  static char arr[10];
  // 假如一直没有遇到字符"l",则向前定位直到跳过6个字符
   // 而如果期间遇到"l",则停止向前,定位在该处
File.ignore(6,'l');
File.read(arr,10);
cout << arr << endl; // 它将显示"lo World!"
File.close();
 }
getline() —— 虽然前面的章节中我曾提到过这个函数,但还有一些内容我们未曾涉及:此函数不但可用于逐行读取,而且它还可以设为遇到某个特定字符后停止读取。下面给出传递这一参数的方法:
getline(array,array_size,delim);
以下为示例代码:
#include <fstream.h>
void main()
  {
    // 假设test_file.txt中已经存有"Hello World"这一内容
    ifstream File("test_file.txt");
static char arr[10];
  /* 读取,直到满足下面的条件之一:
  1)已经读取10个字符
  2)遇到字母"o"
  3)出现新一行
    */
    File.getline(arr,10,'o');
 cout << arr << endl; // 将显示"Hell"
    File.close();
  }
 peek() —— 此函数将返回输入流文件的下一个字符,但它不移动内置指针。我想你该记得,像get()这样的函数也返回输入流文件的下一个字符,而与此同时它将移动内置指针。所以当你再次调用get()函数的时候,它会返回再下一个字符,而非前面那个。哦,使用peek()也会返回字符,但它不会移动"光标"。所以,假如你连续两次调用peek()函数,它会返回同一个字符。考虑以下代码:
 #include <fstream.h>
 void main()
  {
    // 假设test_file.txt中已经存有"Hello World"这一内容
    ifstream File("test_file.txt");
char ch;
 File.get(ch);
    cout << ch << endl; // 将显示"H"
   cout <<  char(File.peek()) << endl; //将显示"e"
    cout <<  char(File.peek()) << endl; //将再次显示"e"
    File.get(ch);
    cout << ch << endl; // 还是显示"e"
    File.close();
     }
    顺便说一下,我忘了讲——peek()函数实质上返回的是字符的ASCII码,而非字符本身。因此,假如你想看到字符本身,你得像我在示例中做的那样进行调用(译注:即要转为char类型)。
   _unlink() —— 删除一个文件。假如你要使用此函数,需要在你的程序中包含io.h头文件。下面是示例代码:
  #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();
   }
   putback() —— 此函数将返回最后一个所读取字符,同时将内置指针移动-1个字符。换言之,如果你使用get()来读取一个字符后再使用putback(),它将为你返回同一个字符,然而同时会将内置指针移动-1个字符,所以你再次使用get()时,它还是会为你返回同样的字符。下面是示例代码:
  #include <fstream.h>
   void main()
  {
    // test_file.txt应包含内容"Hello World"
     ifstream File("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();
  }
   flush() —— 在处理输出流文件的时候,你所存入的数据实际上并非立刻写入文件,而是先放入一个缓冲区中,直到该缓冲区放满数据之后,这些数据才被存入真正的文件中(在你的磁盘上)。旋即缓冲区会被清空,再重新进行下一轮写入。
  但假如你想在缓冲区写满之前就将其中的数据写入磁盘,则使用flush()函数。只须像这样进行调用:FileHandle.flush(),这样缓冲区内的数据将会写入实际的物理文件,而后缓冲区被清空。
  再补充一点(高阶的)内容:flush()函数会调用与相应流缓冲(streambuf)相联系的sync()函数(出自MSDN)。

if (flag==1 || flag==2){ text_pagination(1); } else{ article.innerHTML=Text; }


掌握输入/输出流

 

在这一章里,我会提及一些有用的函数。我将为你演示如何打开一个可以同时进行读、写操作的文件;此外,我还将为你介绍其它打开文件的方法,以及如何判断打开操作是否成功。因此,请接着往下读!

到目前为止,我已为你所展示的只是单一的打开文件的途径:要么为读取而打开,要么为写入而打开。但文件还可以以其它方式打开。迄今,你应当已经认识了下面的方法:

 

ifstream OpenFile(“cpp-home.txt”);

 

噢,这可不是唯一的方法!正如以前所提到的,以上的代码创建一个类ifstream的对象,并将文件的名字传递给它的构造函数。但实际上,还存在有不少的重载的构造函数,它们可以接受不止一个的参数。同时,还有一个open()函数可以做同样的事情。下面是一个以上代码的示例,但它使用了open()函数:

 

ifstream OpenFile;

OpenFile.open(“cpp-home.txt”);

 

你会问:它们之间有什么区别吗?哦,我曾做了不少测试,结论是没有区别!只不过如果你要创建一个文件句柄但不想立刻给它指定一个文件名,那么你可以使用open()函数过后进行指定。顺便再给出一个要使用open()函数的例子:如果你打开一个文件,然后关闭了它,又打算用同一个文件句柄打开另一个文件,这样一来,你将需要使用open()函数。

考虑以下的代码示例:

 

#include <fstream.h>

 

void read(ifstream &T) //pass the file stream to the function

{  

//the method to read a file, that I showed you before

    char ch;

 

    while(!T.eof())

    {

       T.get(ch);

       cout << ch;

    }

   

    cout << endl << "--------" << endl;

}

 

void main()

{

    ifstream T("file1.txt");

    read(T);

    T.close();

 

    T.open("file2.txt");

    read(T);

    T.close();

}

 

据此,只要file1.txt和file2.txt并存储了文本内容,你将看到这些内容。

现在,该向你演示的是,文件名并不是你唯一可以向open()函数或者构造函数(其实都一样)传递的参数。下面是一个函数原型:

 

ifstream OpenFile(char *filename, int open_mode);

 

你应当知道filename表示文件的名称(一个字符串),而新出现的则是open_mode(打开模式)。open_mode的值用来定义以怎样的方式打开文件。下面是打开模式的列表:

名称

描述

ios::in

打开一个可读取文件

ios::out

打开一个可写入文件

ios::app

你写入的所有数据将被追加到文件的末尾,此方式使用ios::out

ios::ate

你写入的所有数据将被追加到文件的末尾,此方式不使用ios::out

ios::trunk

删除文件原来已存在的内容(清空文件)

ios::nocreate

如果要打开的文件并不存在,那么以此参数调用open()函数将无法进行。

ios::noreplace

如果要打开的文件已存在,试图用open()函数打开时将返回一个错误。

ios::binary

以二进制的形式打开一个文件。

 

实际上,以上的值都属于一个枚举类型的int常量。但为了让你的编程生涯不至于太痛苦,你可以像上表所见的那样使用那些名称。

下面是一个关于如何使用打开模式的例子:

 

#include <fstream.h>

 

void main()

{

    ofstream SaveFile("file1.txt", ios::ate);

 

    SaveFile << "That's new!\n";

 

    SaveFile.close();

}

 

正如你在表中所看到的:使用ios::ate将会从文件的末尾开始执行写入。如果我没有使用它,原来的文件内容将会被重新写入的内容覆盖掉。不过既然我已经使用了它,那么我只会在原文件的末尾进行添加。所以,如果file1.txt原有的内容是这样:

Hi! This is test from www.cpp-home.com!

那么执行上面的代码后,程序将会为它添上“That’s new!”,因此它看起来将变成这样:

Hi! This is test from www.cpp-home.com!That’s new!

假如你打算设置不止一个的打开模式标志,只须使用OR操作符或者是 | ,像这样:

 

ios::ate | ios::binary

 

我希望现在你已经明白“打开模式”是什么意思了!

现在,是时候向你展示一些真正有用的东西了!我敢打赌你现在还不知道应当怎样打开一个可以同时进行读取和写入操作的文件!下面就是实现的方法:

 

fstream File(“cpp-home.txt”,ios::in | ios::out);

 

实际上,这只是一个声明语句。我将在下面数行之后给你一个代码示例。但此时我首先想提及一些你应当知道的内容。

上面的代码创建了一个名为“File”的流式文件的句柄。如你所知,它是fstream类的一个对象。当使用fstream时,你应当指定ios::in和ios::out作为文件的打开模式。这样,你就可以同时对文件进行读、写,而无须创建新的文件句柄。噢,当然,你也可以只进行读或者写的操作。那样的话,相应地你应当只使用ios::in或者只使用ios::out —— 要思考的问题是:如果你打算这么做,为什么你不分别用ifstream及ofstream来实现呢?

下面就先给出示例代码:

 

#include <fstream.h>

 

void main()
{

    fstream File("test.txt",ios::in | ios::out);

 

    File << "Hi!"; //将“Hi!”写入文件

    static char str[10]; //当使用static时,数组会自动被初始化

                //即是被清空为零



    File.seekg(ios::beg); // 回到文件首部

                  // 此函数将在后面解释

    File >> str;

    cout << str << endl;

 

    File.close();
}

 

OK,这儿又有一些新东西,所以我将逐行进行解释:

 

fstream File(“test.txt”, ios::in | ios::out); —— 此行创建一个fstream对象,执行时将会以读/写方式打开test.txt文件。这意味着你可以同时读取文件并写入数据。

 

File << “Hi!”; —— 我打赌你已经知道它的意思了。

 

static char str[10]; —— 这将创建一个容量为10的字符数组。我猜static对你而言或者有些陌生,如果这样就忽略它。这只不过会在创建数组的同时对其进行初始化。

 

File.seekg(ios::beg); —— OK,我要让你明白它究竟会做些什么,因此我将以一些有点儿离题、但挺重要的内容开始我的解释。

还记得它么:

 

while(!OpenFile.eof())

    {

       OpenFile.get(ch);

       cout << ch;

    }

 

你是不是曾经很想知道那背后真正执行了什么操作?不管是或不是,我都将为你解释。这是一个while型循环,它会一直反复,直至程序的操作到达文件的尾端。但这个循环如何知道是否已经到了文件末尾?嗯,当你读文件的时候,会有一个类似于“内置指针(inside-pointer)”的东西,它表明你读取(写入也一样)已经到了文件的哪个位置,就像记事本中的光标。而每当你调用OpenFile.get(ch)的时候,它会返回当前位置的字符,存储在ch变量中,并将这一内置指针向前移动一个字符。因此下次该函数再被调用时,它将会返回下一个字符。而这一过程将不断反复,直到读取到达文件尾。所以,让我们回到那行代码:函数seekg()将把内置指针定位到指定的位置(依你决定)。你可以使用:

 

ios::beg —— 可将它移动到文件首端

ios::end —— 可将它移动到文件末端

 

或者,你可以设定向前或向后跳转的字符数。例如,如果你要向定位到当前位置的5个字符以前,你应当写:

File.seekg(-5);

如果你想向后跳过40个字符,则应当写:

File.seekg(40);

同时,我必须指出,函数seekg()是被重载的,它也可以带两个参数。另一个版本是这样子的:

File.seekg(-5,ios::end);

在这个例子中,你将能够读到文件文本的最后4个字符,因为:

1)你先到达了末尾(ios::end)

2)你接着到达了末尾的前五个字符的位置(-5)

为什么你会读到4个字符而不是5个?噢,只须把最后一个看成是“丢掉了”,因为文件最末端的“东西”既不是字符也不是空白符,那只是一个位置(译注:或许ios::end所“指”的根本已经超出了文件本身的范围,确切的说它是指向文件最后一个字符的下一个位置,有点类似STL中的各个容器的end迭代点是指向最后一个元素的下一位置。这样设计可能是便于在循环中实现遍历)。

你现在可能想知道为什么我要使用到这个函数。呃,当我把“Hi”写进文件之后,内置指针将被设为指向其后面……也就是文件的末尾。因此我必须将内置指针设回文件起始处。这就是这个函数在此处的确切用途。

File >> str; —— 这也是新鲜的玩意儿!噢,我确信这行代码让你想起了cin >> .实际上,它们之间有着相当的关联。此行会从文件中读取一个单词,然后将它存入指定的数组变量中。

例如,如果文件中有这样的文本片断:

Hi! Do you know me?

使用File >> str,则只会将“Hi!”输出到str数组中。你应当已经注意到了,它实际上是将空格作为单词的分隔符进行读取的。

由于我存入文件中的只是单独一个“Hi!”,我不需要写一个while循环,那会花费更多的时间来写代码。这就是我使用此方法的原因。顺便说一下,到目前为止,我所使用的读取文件的while循环中,程序读文件的方式是一个字符一个字符进行读取的。然而你也可以一个单词一个单词地进行读取,像这样:

 

char str[30]; // 每个单词的长度不能超过30个字符

while(!OpenFile.eof())

    {

       OpenFile >> str;

       cout << str;

    }

 

你也可以一行一行地进行读取,像这样:

 

char line[100]; // 每个整行将会陆续被存储在这里
while(!OpenFile.eof())
{

OpenFile.getline(line,100); // 100是数组的大小

cout << line << endl;
}

 

你现在可能想知道应当使用哪种方法。嗯,我建议你使用逐行读取的方式,或者是最初我提及的逐字符读取的方式。而逐词读取的方式并非一个好的方案,因为它不会读出新起一行这样的信息,所以如果你的文件中新起一行时,它将不会将那些内容新起一行进行显示,而是加在已经打印的文本后面。而使用getline()或者get()都将会向你展现出文件的本来面目!

现在,我将向你介绍如何检测文件打开操作是否成功。实现上,好的方法少之又少,我将都会涉及它们。需要注意的是,出现“X”的时候,它实际可以以“o”、 “i”来代替,或者也可以什么都不是(那将是一个fstream对象)。

例1:最通常的作法

 

Xfstream File(“cpp-home.txt”);

if (!File)
{

cout << “Error opening the file! Aborting…\n”;

exit(1);
}

 

 

例2:如果文件已经被创建,返回一个错误

 

ofstream File("unexisting.txt", ios::nocreate);

 

if(!File)

{

cout << “Error opening the file! Aborting…\n”;

exit(1);

}

 

例3:使用fail()函数

 

ofstream File("filer.txt", ios::nocreate);

 

if(File.fail())

{

cout << “Error opening the file! Aborting…\n”;

exit(1);

}

 

例3中的新出现的东西,是fail()函数。如果有任何输入/输出错误(不是在文件末尾)发生,它将返回非零值。

我也要讲一些我认为非常重要的内容!例如,如果你已经创建一个流文件对象,但你没有进行打开文件操作,像这样:

 

ifstream File; //也可以是一个ofstream

 

这样,我们就拥有一个文件句柄,但我们仍然没有打开文件。如果你打算迟些打开它,那么可以用open()函数来实现,我已经在本教程中将它介绍了。但如果在你的程序的某处,你可能需要知道当前的句柄是否关联了一个已经打开的文件,那么你可以用is_open()来进行检测。如果文件没有打开,它将返回0 (false);如果文件已经打开,它将返回1 (true


c++文件操作过程包括一下5个步骤:

(1) 在程序中包含头文件fstream.h或fstream

#include<fstream.h>

(2) 定义文件流变量

ifstream inData; //定义输入文件流变量

ofstream outData;//定义输出文件流变量

(3)将文件流变量与磁盘文件关联起来

fileVar.open(filename,mode)

fileVar 是第(2)部定义的文件流变量,filename是磁盘文件名,mode是打开或建立文件的方式,可以是:

ios::in   打开输入文件,iftream类型变量的默认方式

ios::out 建立输出文件 ofstream类型变量的默认方式

ios::app  增加方式,若文件存在,将在文件尾增加数据;若不存在,就建立文件

ios:trunk  若文件存在,文件中已有的内容将被清除

ios::nocreate 若文件不存在,打开操作失败

ios::noreplace  若文件存在 ,打开操作失败

(4) 用文件流(<< or>>)操作文件,读/写文件数据

将输入流文件变量与>>连接就能够从文件读入数据,与cin用法相同。将输出文件流变量与<<连接,就能够将数据输出到文件中,与cout用法相同。

(5) 关闭文件

文件操作文件完成后,应该关闭文件。关闭文件时,系统会立即将文件缓冲区中的数组写回磁盘文件,并且断开文件流变量与磁盘之间的联系。关闭文件的方法如下:

inData();//inData输入文件流变量

outData();//'outData是输出文件流变量

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值