文件操作:1入门

•1.概念:

  c++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h

  fstream:可同时读写操作的文件类(由iostream引申而来)

  ofsteam:可操作(输出)的文件类(由ostream引申而来)

  ifstream:读操作(输入)的文件类(由istream引申而来)

•2.文件中数据的组织形式:

  文件可以分为:

  1.ASCII文件

      ASCII文件也称文本文件,其每个字节存一个ASCII代码,表示一个字符

      优点:便于对字符操作

      缺点:占用的存储空间较大、速度慢

  2.二进制文件

      把内存中的存储形式原样写到外存储器中

      优点:节省外存储空间和转换时间、速度快、便于存放中间结果

      缺点:一个字节不对应一个字符

  举例:int型数10000

      在内存存储形式0010 0111 0001 0000

      ASCII形式0011 0001 0011 0000 0011 0000 0011 0000 0011 0000

      二进制形式0010 0111 0001 0000(10000的二进制表示)

•3.打开文件:

  创建文件流对象:为了实现文件的输入输出,首先要创建一个文件流,把这个流和实际的文件相关联 

           ofstream outfile;//建立一个输出文件流对象outfile

             ifstream infile;//建立一个输入文件流对象infile

     注意:建立文件流对象要包含头文件:fstream.h

       补充:要通过一个流对象打开一个文件,要使用它的成员函数open()

          使用的语句:void open(const char *filename,openmode mode);//其中filename是要打开的文件名,mode是打开文件的方式

            打开文件的方式总结:

ios::app 以追加方式打开文件
ios::ate 文件打开后定位到文件尾
ios::binary 以二进制方式打开文件,缺省的方式是文本
ios::in 文件以输入方式打开(ifstream默认的)
ios::out

文件以输出方式打开(ofstream默认)

ios::nocreate 不建立文件,所以文件不存在时打开失败
ios::noreplace 不覆盖文件,所以打开文件时如果文件存在,则失败
ios::trunc 如果文件存在,把文件长度设置为0

               

     以上属性用"|"连接

     ofstream、ifstream、fstream所有这些类的成员函数open都包含了一个默认的打开文件的方式,如下表:

参数的默认方式
ofstream ios::out|ios::trunc
ifstream ios::in
fstream ios::i|ios::out

   

    当函数被调用时没有声明方式参数的情况下,默认值才会被采用。若被调用时声明了方式,默认值将被完全改写,不会与 参数组合。

    例如:以二进制输入方式打开文件c:\config.sys

    

    fstream file1;

    file1.open("c:\\config.sys",ios::binary|ios::in);

    说明:打开文件用于输入,并将这个文件与输入文件类对象infile建立联系,今后,在程序中,用到这个文件"config.sys"的地方用fiel1来代替。

    或者为:fstream file1("c:\\config.sys",ios::binary|ios::in);

        注意:若省略文件路径,默认为当前源文件目录下的文件。

          

     打开文件后,都要判断打开是否成功。

      若打开成功,文件流对象值为非零值

      若打开失败,则其值为0

      

      你可以通过调用成员函数is_open()来检查一个文件是否已经被顺利的打开了:

        bool is_open();

      它返回一个布尔(bool)值,为真(true)代表文件已经被顺利打开,假( false )则相反。

      示例:

 1 fstream pfile1,pfile2;//定义2个文件类对象
 2 
 3         pfile1.open("file1.txt",ios::in);//以输入方式打开文件
 4 
 5         pfile2.open("file2.txt",ios::out);//以输出方式打开文件
 6 
 7         if(!pfile1)//或者写成if(!pfile1.is_open())
 8 
 9           {cout<<"不能打开输入文件:file1.txt"<<'\n';}
10 
11         if(!pfile2)//或者写成if(!pfile2.is_open())
12 
13           {cout<<"不能打开输出文件:file2.txt"<<'\n';}
14 
15 打开文件
打开文件

     

•4.关闭文件
    打开文件使用完后一定要关闭,fstream提供了成员函数close()来完成此操作。

      例如:file1.close();//把与file1对象相连的文件关闭。

好啦,上面的概念性的东西介绍好了~~,下面就来介绍一些方法步骤以及一些实质性的代码吧~

•一:文本文件的读写:

    用插入器(<<)向文件输出

    用析取器(>>)向文件输入

1.文件的输出操作(写):

将程序中的数据输出到文件中,需要下面5个步骤:

   1.包含fstream头文件:#include<fstream>

   2.建立ofstream对象:ofstream ofile;

   3.将对象与文件关联:ofile.open("test.txt");

   4.使用该对象将数据输出到文件test中:

      ofile<<"Hello,C++!";

     5.关闭与文件的连接:ofile.close(); 

   p.s:这里用ofstream对象ocout将数据直接输出到文件中,而不是屏幕上!

    程序示例:

    

 1 #include <fstream>
 2 using namespace std;
 3  
 4 int main()
 5 {
 6     ofstream ocout;
 7     ocout.open("test.txt");
 8     ocout<<"Hello,C++!";
 9     ocout.close();
10     return 0;
11 }
数据写入文件

 运行程序,看到程序目录下有一个test.txt文件,打开文件显示"Hello,C++!"。

 特别注意的是,我们也可以把上面程序的第6和第7行合并为一句话:

    

    ofstream ocout("test.txt");
      解释: 这句话的意思就是调用ofstream类中的构造函数来创建这个文本文件。另外,我们需要特别注意一点,在完成对整个文件的操作之后,一定要用close()函数将这个文件关闭了,否则在程序结束后,所操作的文件将什么都不会保存下来!!!我们在调用文件流函数close()的作用是关闭文件并且保护数据。这样就保证以后的操作不会对文件产生影响。因为该文件已经被关闭了。的确close是为了保护写入数据时不被干扰,如果没有关闭,认为仍在写入状态,无法读入吧。这是因为在程序没有结束的时候,系统是不会自动调用close()函数来将缓冲区中的数据存储到磁盘文件上的
 
2.读取文件中数据
  打开文件读取数据的方法和输出数据到文集中的方法基本上是一样的,同样也需要5个步骤:

   1包含fstream头文件:#include <fstream>

  2建立ifstream对象:ifstream icin;

  3将对象与文件关联:icin.open(“test.txt”);

  4使用该对象读取文件test中的数据到数组temp中:icin>>temp;

  5关闭与文件的连接:icin.close();

    程序示例:

 1 #include <fstream>
 2 #include <iostream>
 3 using namespace std;
 4  
 5 int main()
 6 {
 7     ifstream icin;
 8     icin.open("test.txt");
 9     char temp[100];//定义一个字符数组temp
10     icin>>temp;//将文件中的数据读到字符数组temp中
11     cout<<temp<<endl;//将temp中存放的内容输出到屏幕上
12     return 0;
13 }
读取本地文件到屏幕

     p.s同上面一样,我们也可以将第2步和第3步合并成一句话:

    ifstream icin("test.txt");

   它的作用就是调用ifstream类中的构造函数来读取这个本地的文本文件。  运行之前,我们需要在该文件夹下建立test.txt文件,其中的内容就是上面的“Hello,C++!”。可以看到,程序在命令行中显示出来了test.txt文本文件中的内容。

3.读取空格和空格后面的字符

  我们在写文件的时候,空格是不可避免的。但是由于C++的插入操作符有一个毛病,它只要一遇到空字符便会停止输出。这里的空字符就是空格,或者是’\0’。那么这样一来,如果我们在文件中有空格字符,那么空格后面的字符就无法被输出到屏幕上了。比如说,我们建立的test.txt文件中的内容为:Hello  C++!即把Hello后面的逗号改成空格,那么重新运行该程序,输出如下:Hello

那么有没有什么解决方法呢,当然是有的哈。用getline()函数嘛。下面粘一段MSDN上面关于getline()函数原型和参数的介绍哈:

 1 template<class CharType, class Traits, class Allocator>
 2    basic_istream<CharType, Traits>& getline(
 3       basic_istream<CharType, Traits>& _Istr,
 4       basic_string<CharType, Traits, Allocator>& _Str
 5 );
 6 
 7 template<class CharType, class Traits, class Allocator>
 8    basic_istream<CharType, Traits>& getline(
 9       basic_istream<CharType, Traits>& _Istr,
10       basic_string<CharType, Traits, Allocator>& _Str,
11       const CharType _Delim
12 );
getline()函数原型

函数中的参数已经用黑体表示出来了哈,下面是参数说明:

 1 _Istr 
 2 The input stream from which a string is to be extracted. 
 3 指明输出的缓冲区是谁
 4 
 5 _Str 
 6 The string into which are read the characters from the input stream. 
 7 读取到流中的字符数据
 8 
 9 _Delim 
10 The line delimiter. 
11 结束符号 
12 (默认的结束符号是’\n’,而这里采用自定义的结束符号替换掉默认的结束符号。意思就是输出遇到_Delim才会停止输出)
参数说明

好了,有了这个函数,我们就可以把上面的程序中的第10行改成:

    icin.getline(temp,100);

OK~~这样一来,我们就不怕文件中有空格了。

      另外,如果我们想要在命令行中写一段话,而且这段换中包含了空格和回车,那么我们就应该利用上面getline()函数的第三个参数,因为一段话中有可能会有回车的出现,我们就必须利用getline()的第三个函数将默认的结束符号’\n’换成空字符‘\0’。这是由于空字符的ASCII码为0,我们不可能在文件中输入空字符,因此这个时候,getline()函数会一直读取到文件的末尾才会结束。而如何停止用户输入呢?方法其实很简单,在我们输入完一段话之后,肯定会按下回车。之后我们就应该向该函数发出EOF标志,即文件结束符标志(End  Of File)。在命令行里面发送文件结束符的方法是“Ctrl+Z”,之后再次按下回车键就能停止输入了。        p.s.  空格不是空字符,它的ASCII码为32。

      下面,咱们用一个实际的例子来演示一下:首先读取一段话,然后将其输出到文件中:

 1 #include <iostream>
 2 #include <fstream>
 3 using namespace std;
 4  
 5 int main()
 6 {
 7     const int num=255;
 8     char temp1[num]={0};//初始化数组temp1
 9     char temp2[num]={0};//初始化数组temp2
10     //① 输出数据到文件text.txt中
11     ofstream f_out("text.txt");
12     cout<<"请输入文本的内容:\n";
13     cin.getline(temp1,num,0);
14     f_out<<temp1;
15     f_out.close();
16     //② 将文件text.txt中的内容重新读回屏幕上
17     ifstream f_in("text.txt");
18     f_in.getline(temp2,num,0);
19     cout<<temp2<<endl;
20     return 0;
21 }
ctrl+z结束符

  对整个程序的分析:
①  输出数据到文件text.txt中
      首先我们在第11行定义了一个文件的输出流对象f_out,并用该对象创建了一个text.txt文本文件。之后在程序的第13行采用getline()函数接受文本内容,并将其放到temp1字符数组中。注意,这里的getline()函数的第三个参数为空字符,说明它可以接受空格,并且只有达到文件的末尾才能停止读取用户的键盘输入。好了,如果我们输入完文件之后按下Ctrl+Z,那么接着再次按下Enter回车键就会停止输入。之后在程序的第14行,我们用ofstream的对象fout将缓冲区中的内容输出到文本文件text.txt中。最后关闭这个文件。
②  将文件text.txt中的内容重新读回屏幕上
      同输出一样,首先我们在程序的第17行定义了一个文件的输入流对象f_in,并用该对象读取了刚刚创建的text.txt文本文件。之后又调用getlin()函数将文件中的内容输出到了字符数组temp2中,之后运用cout来输出temp2数组的内容到屏幕上。这样一来,我们就完成了对文件的输入输出操作。

OK啦!!!程序输出成功咯!!但是这个程序还有一个小小的瑕疵,注意看上面输出结果,我们可以看到在命令行中“请按任意键继续…”上面居然还有一个回车!这是怎么回事呢?我们并没有在多输出一个回车啊?

      其实是有的!!!!注意,我们在“!”之后回了一次车,然后才输出了ctrl+Z,向getline()函数发送了一个文件结束的标志。之后为了让程序结束,又按了一下回车。那么这里面第2次按下的回车由于超出了文件结束符EOF被自动抛弃了,但是,第一次按下的回车,就是!之后的那个回车却没有被丢弃掉,而是被写入了temp1函数中。这个就是问题的所在。所以我们在输出之后,会看到在“请按任意键继续…”上面居然还有一个回车!对于这个问题,解决方法其实很简单,我们只需要把最后一个Enter改成空字符’\0’就可以了。即在程序的13行之后添加上这样两句话:

1 int n=strlen(temp1);
2 temp1[n-1]='\0';
View Code

第一句话的意思就是读取字符数组temp1中可见字符的长度,并保存到整型变量n中;第二句话的意思就是找到保存Enter键的元素的下标,然后将这个下标的元素赋值成空字符就可以了。完整的程序如下:

 1 #include <iostream>
 2 #include <fstream>
 3 using namespace std;
 4  
 5 int main()
 6 {
 7     const int num=255;
 8     char temp1[num]={0};//初始化数组temp1
 9     char temp2[num]={0};//初始化数组temp2
10     //① 输出数据到文件text.txt中
11     ofstream f_out("text.txt");
12     cout<<"请输入文本的内容:\n";
13     cin.getline(temp1,num,0);
14     int n=strlen(temp1);
15     temp1[n-1]='\0';
16     f_out<<temp1;
17     f_out.close();
18     //② 将文件text.txt中的内容重新读回屏幕上
19     ifstream f_in("text.txt");
20     f_in.getline(temp2,num,0);
21     cout<<temp2<<endl;
22     return 0;
23 }
View Code

啊哈哈哈,这篇博客真的好长,不过确实学到东西了,下面继续学习文件的操作~~

 

 

 

 

    

posted @ 2015-02-01 13:18  BAOXF  阅读(392)  评论(0编辑  收藏  举报