C++学习笔记之对文件的操作

===========================前言===========================

       我们在编写程序的时候,最密不可分的就是对文件进行相应的操作,我们可以从文件中读取数据,可以将数据保存到文件,可以……

       总而言之,言而总之,一言以蔽之,对文件的操作是非常重要的,下面我们就来介绍一下C++中是如何对文件进行操作的。

===========================功能展示===========================

  • 文件的输出操作

       想要程序中的数据输出到文件中,一共需要以下5个步骤:

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

建立ofstream对象:ofstream ocout;

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

使用该对象将数据输出到文件test中:ocout<<”Hello,C++!”;

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

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

完整程序示例:

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

      运行程序后,我们就会在程序的目录下发现一个test.txt文件,打开之后会显示“Hello,C++!”。如下图所示

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

?
ofstream ocout( "test.txt" );

      这句话的意思就是调用ofstream类中的构造函数来创建这个文本文件。另外,我们需要特别注意一点,在完成对整个文件的操作之后,一定要用close()函数将这个文件关闭了,否则在程序结束后,所操作的文件将什么都不会保存下来!!!

  • 读取文件中的数据

       打开文件读取数据的方法和输出数据到文集中的方法基本上是一样的,同样也需要5个步骤:

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

建立ifstream对象:ifstream icin;

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

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

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

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

?
ifstream icin( "test.txt" );

      它的作用就是调用ifstream类中的构造函数来读取这个本地的文本文件。

完整的程序示例:

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

      运行之前,我们需要在该文件夹下建立test.txt文件,其中的内容就是上面的“Hello,C++!”。那么输出如下:

      可以看到,程序在命令行中显示出来了test.txt文本文件中的内容。

  • 如何读取空格和空格后面的字符  

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

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

首先是函数原型:

复制代码
template<class CharType, class Traits, class Allocator>
   basic_istream<CharType, Traits>& getline(
      basic_istream<CharType, Traits>& _Istr,
      basic_string<CharType, Traits, Allocator>& _Str
);

template<class CharType, class Traits, class Allocator>
   basic_istream<CharType, Traits>& getline(
      basic_istream<CharType, Traits>& _Istr,
      basic_string<CharType, Traits, Allocator>& _Str,
      const CharType _Delim
); 
复制代码

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

复制代码
_Istr 
The input stream from which a string is to be extracted. 
指明输出的缓冲区是谁

_Str 
The string into which are read the characters from the input stream. 
读取到流中的字符数据

_Delim 
The line delimiter. 
结束符号 
(默认的结束符号是’\n’,而这里采用自定义的结束符号替换掉默认的结束符号。意思就是输出遇到_Delim才会停止输出)
复制代码

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

?
icin.getline(temp,100);

这就表示把字符数组temp中的内容全部读取到屏幕上,如下图所示

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

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

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

?
#include <iostream>
#include <fstream>
using namespace std;
  
int main()
{
     const int num=255;
     char temp1[num]={0}; //初始化数组temp1
     char temp2[num]={0}; //初始化数组temp2
     //① 输出数据到文件text.txt中
     ofstream f_out( "text.txt" );
     cout<< "请输入文本的内容:\n" ;
     cin.getline(temp1,num,0);
     f_out<<temp1;
     f_out.close();
     //② 将文件text.txt中的内容重新读回屏幕上
     ifstream f_in( "text.txt" );
     f_in.getline(temp2,num,0);
     cout<<temp2<<endl;
     return 0;
}

      对整个程序的分析:
① 输出数据到文件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
2
int n= strlen (temp1);
temp1[n-1]= '\0' ;

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

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

  然后是程序的输出:

       好了,终于把这个程序搞定了,好麻烦!!!呼呼~~

===========================功能展示==========================

  • 打开文件的方式

      当我们想要打开的文件不存在的时候,一般地,ofstream类的对象会默认地自动创建一个文件。而如果我们想要打开的文件是存在的,那么就会调用ofstream的构造函数或者是调用open()函数进行打开。下面,我们来看一下MSDN上面是如何定义open()函数的:

首先是函数原型:

复制代码
void open(
    const char *_Filename,
    ios_base::openmode _Mode = ios_base::in | ios_base::out,
    int _Prot = (int)ios_base::_Openprot
);
void open(
    const char *_Filename,
    ios_base::openmode _Mode
);
void open(
    const wchar_t *_Filename,
    ios_base::openmode _Mode = ios_base::in | ios_base::out,
    int _Prot = (int)ios_base::_Openprot
);
void open(
    const wchar_t *_Filename,
    ios_base::openmode _Mode
);
复制代码

接下来是参数的说明:

复制代码
_Filename
The name of the file to open.
打开文件名

_Mode
One of the enumerations in ios_base::openmode.
文件的打开方式(在ios_base::openmode中定义)

_Prot
The default file opening protection.
默认进行文件打开时的保护
复制代码

OK,我们再来看看ios_base::openmode中定义的打开方式:

复制代码
ios::in, to permit extraction from a stream.
打开文件进行读操作,即读取文件中的数据

ios::out, to permit insertion to a stream.
打开文件进行写操作,即输出数据到文件中

ios::app, to seek to the end of a stream before each insertion.
打开文件之后文件指针指向文件末尾,只能在文件末尾进行数据的写入

ios::ate, to seek to the end of a stream when its controlling object is first created.
打开文件之后文件指针指向文件末尾,但是可以在文件的任何地方进行数据的写入

ios::trunc, to delete contents of an existing file when its controlling object is created.
默认的文件打开方式,若文件已经存在,则清空文件的内容

ios::binary, to read a file as a binary stream, rather than as a text stream.
打开文件为二进制文件,否则为文本文件
复制代码

      好了,open()函数的用法全部列举出来了。下面就针对ios_base::binary的二进制打开方式,我们在来谈一谈二进制文件的输出方式和文本文件的输出方式。

      ① 文本形式输出到文件,我们完全可以在open函数的mode选项中调用

?
ios::out|ios::app

      好了,上面这句话说的就是将数据依次输出。注意,这里用的是依次,原因就是我们采用了app(append)模式,此表示在文件末尾继续写入文件,这就实现了数据的挨个写入 ^_^。一个完整的程序例子如下:

?
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 <iostream>
#include<fstream>
using namespace std;
const int num=20;
struct people
{
     char name[num];
     double weight;
     int tall;
     int age;
     char sex;
};
int main()
{
     people pe={ "李勇" ,78.5,181,25, 'f' };
     ofstream fout( "people.txt" ,ios::out|ios::app);
     fout<<pe.name<< " " <<pe.age<< " " <<pe.sex<< " " <<pe.tall<< " " <<pe.weight<< " " << "\n" ;
     fout.close();
     ifstream fin( "people.txt" );
     char ch[255];
     fin.getline(ch,255-1,0);
     cout<<ch;
     fin.close();
     return 0;
}

  输出如下:

      我们可以看到,people.txt文件中的内容和命令行中的一样。

      ② 二进制形式输出到文件 为了能够让其用二进制方式输出文件,我们只需要把上面程序的第16行和17行换做

?
1
2
ofstream fout( "people.txt" ,ios::binary);
fout.write(( char *)&pe, sizeof pe);

  程序的第1行中的标志binary用于开启二进制模式,第2行调用了write函数。该函数有两个参数,第一个是要写入数据的首地址,在这里是结构体pe的地址,而第二个参数是要写入的字符数目,这里我们用sizeof来计算pe的字符数。具体程序如下:

?
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
26
#include <iostream>
#include<fstream>
using namespace std;
const int num=20;
struct people
{
     char name[num];
     double weight;
     int tall;
     int age;
     char sex;
};
int main()
{
     people pe={ "李勇" ,78.5,181,25, 'f' };
     ofstream fout( "people.txt" ,ios::binary);
     fout.write(( char *)&pe, sizeof pe);
     fout.close();
     people pe1={ "张玲" ,65.4,165,62, 'm' };
     ifstream fin( "people.txt" ,ios::binary);
     fin.read(( char *)&pe1, sizeof pe1);
     cout<<pe1.name<< " " <<pe1.age<< " " <<pe1.sex<< " " <<pe1.tall<< " " 
         << pe1.weight << " " << "\n" ;
     fin.close();
     return 0;
}

      我们再来看看这个东东的输出,我们可以看到,以txt文档打开文件时候,会产生乱码。这就是因为txt文件是以文本方式打开的,所以我们看到的都是乱码。如下图:

呼呼,以上就是我自认的自己不是很懂的C++关于如何操作文件的记录,到这里了~~全文完 ^_^

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1.如何设置全局变量?                            在 .h文件里定义变量,然后在process的HEAD BLOCK 里include这个头文件,就可以使用全局变量了。   2.OPNET中如何更方便的看程序? 1.opnet中的设置:   preferences->editor_prog        2.source insight的设置  :operation->preferences->symbol Lookups->Project symbol path->Add Project to   Path  (添加自己创建一个包含所有opnet model 和 include目录的project)  当然,这个有些不足,就是那个sv,tv,hb等中定义的内容,不能进行关联。     3.OPNET中的函数FIN,FRET以及FOUT都是什么功能?    为了使一个用户定义的函数被执行,该函数必须与一个特殊的堆栈跟踪代码相连。堆栈跟踪技术靠在函数的入口点和出口点插入预处理器宏指令完成(一个函数只有一个入口点,但可以有多个出口点(由C语言的return声明决定))。这些宏指令为:FIN、FOUT和FRET。FIN被插入到函数的入口点,FOUT被插入到函数的出口点,但却不返回任何值,FRET被插入到函数的出口点,返回一个值。注意这些宏指令不需要以分号结束(它们自我包含),FIN的参数中也不需要双引号。    Opnet提供的所有的示例模型都包含了这些宏指令,并且建议用户定义的函数也包含这些宏指令。如果FIN、FOUT、和FRET被正确插入了用户代码中,我们就可以使用op_vuerr来找出程序错误的位置,哪怕是在一个嵌套的模型函数调用中。  

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值