heu是什么意思
上一课《第一部分第九课:数组威武,动静合一》中,我们学习了动态数组和静态数组,也看到其实字符串很类似字符数组。到目前为止,我们写的程序还比较简单,当然了,因为我们刚开始学习c++嘛。但只要加以训练,我们就慢慢地能够写一些真正的应用了。我们也开始逐渐了解c++的基础知识了,不过缺了很重要的一环:与文件交互。我们已经学会如何将信息输出到控制台以及如何提取用户在控制台中输入的数据。但是,我们岂能就此罢休。想想我们之前介绍过的一些程序,例如:记事本,一些ide,绘图软件,等等,都能够读写文件。在游戏领域就更是如此啦:游戏里的数据要保存,游戏的图片,音乐,道具,等等。总之,如果一个软件不会与文件交互,那么它的功能是比较有限的。我们要读写文件,首先需要打开文件。就好像平时我们要记笔记一样,你总得先打开笔记本吧,才能阅读内容,或者往里面写东西。用术语来说,我们会将一个程序和外界的通信方式用'流'来描述。而这里的iostream就是input output stream的缩写,表示'输入输出流'。因此,我们需要用到fstream这个标准库,fstream就是file stream的缩写。运行此程序,不出意外的话,你的电脑的c:/cpp/files/目录下就会多出一个文件 , 里面的内容如下所示:
文件读写,海阔凭鱼跃
上一课《【c++探索之旅】第一部分第九课:数组威武,动静合一》中,我们学习了动态数组和静态数组,也看到其实字符串很类似字符数组(到了之后的第二部分,学习面向对象,我们会知道其实string是一个类)。
到目前为止,我们写的程序还比较简单,当然了,因为我们刚开始学习c++嘛。但只要加以训练,我们就慢慢地能够写一些真正的应用了。我们也开始逐渐了解c++的基础知识了,不过缺了很重要的一环:与文件交互。
我们已经学会如何将信息输出到控制台(console)以及如何提取用户在控制台中输入的数据(使用cin和cout)。但是,我们岂能就此罢休。想想我们之前介绍过的一些程序,例如:记事本,一些ide(vs, codeblocks, xcode, eclipse, etc),绘图软件,等等,都能够读写文件。
在游戏领域就更是如此啦(我知道一帮宅男已经激动了):游戏里的数据要保存,游戏的图片,音乐,道具,等等。都需要存档。
总之,如果一个软件不会与文件交互,那么它的功能是比较有限的。
因此,一起来学习如何读写文件吧。你会发现,如果你掌握了cin和cout的用法,那其实你已经知道大半啦。
我们要读写文件,首先需要打开文件。就好像平时我们要记笔记一样,你总得先打开笔记本吧,才能阅读内容,或者往里面写东西。
一旦文件被打开之后,接下来的操作就很类似之前用cin和cout来进行标准输入和输出了。我们又会与老朋友和>>见面。
用术语来说,我们会将一个程序和外界的通信方式用"流"来描述。流,英语是stream。记得吗?我们要使用cin和cout,需要用
#include iostream>
因为cin和cout定义在iostream这个c++的标准库中。而这里的iostream就是input output stream的缩写,表示"输入输出流"。所以,其实我们早就在不知不觉地接触流的概念了。
在这一章中,我们要和文件交互,那么就需要文件流来帮忙了。聪明如你一定想到了,是的,文件的英语是file,那么文件流就是file stream。是不是很简单呢?
因此,我们需要用到fstream这个标准库,fstream就是file stream的缩写。
当然了,如果你不是参加一个程序员的派对,也不需要显得很专业,那么说"读写文件"就可以了。
在c++中,我们要使用一个功能,需要引入合适的头文件。因此,我们在程序一开始须要这样做:
#include fstream>
接下来,我们就学习如何创建一个文件流,以便我们能读写文件。
流其实是对象,还记得我们说c++是一门面向对象的语言吗?当然我们现在还不深究,要到第二部分讲面向对象编程时才会畅聊类和对象。暂时只需要知道这些流其实都是c++的对象(不是找对象的对象,少年你想多了)。
也完全无需害怕,因为我们之后还会不断提到流。暂时,只需把其看作比较高级的变量就可以了。这些文件流包含了文件的很多信息,提供给我们很多功能,例如可以关闭文件,在文件中移动,等等。
你会看到,声明一个流的对象,其实就和我们声明变量一样简单。首先,我们来看看如何创建用于写文件的流,须要用到ofstream,也就是output file stream,因为是从程序向文件输入数据,因此对于程序来说是"出去"的流,因此是output(输出),而不是input(输入)。
话休絮烦。翠花,上"栗子":
#include iostream>
#include fstream>
using namespace std;
int main()
{
ofstream mystream("c:/cpp/files/");
//声明用于写入文件的流,文件
return 0;
}
在上面程序中,我在mystream后面的括号中指定了文件的路径.这个路径可以有两种形式:
自此,我们就可以使用这个文件流来写文件啦。
如果文件不存在,那么会被自动创建。不过,至少指定的目录要存在,不然会出现"目录不存在"的错误。在我们上面的例子中,至少目录c:/cpp/files必须事先存在。
在打开文件的时候,也会有其他问题。例如文件不属于你,或者磁盘已满,等等,总之,打开失败。因此,我们为了保险起见,总要测试文件是否顺利被打开。我们使用 if (mystream) 的方法来测试。
ofstream mystream("c:/cpp/files/"); //试着打开这个文件
if(mystream) //测试打开文件是否成功
{
//一切顺利,我们可以使用此文件了
}
else
{
cout "出错: 无法打开此文件." endl;
}
至此,我们已经做好了写文件的准备工作。你会看到,接下来的操作还是有点眼熟的。
前面我们说过写入文件的操作就和以前我们使用cout类似。因此当我对你说要使用运算符来进行操作的时候,你应该不会太惊讶。
#include iostream>
#include fstream>
#include string>
using namespace std;
int main()
{
string const filename("c:/cpp/files/");
ofstream mystream(filename.c_str());
if(mystream)
{
mystream "大家好,我是被写入文件的一句话." endl;
mystream 54.26 endl;
int age(23);
mystream "我" age "岁了." endl;
}
else
{
cout "出错: 无法打开此文件." endl;
}
return 0;
}
上面的程序中,可以看到我们首先声明了一个string的变量,里面存放了c:/cpp/files/这个字符串,不过之后在将其赋给ofstream的对象mystream时,我们却用了c_str()这个函数,这是为什么呢?
其实,ofstream接受的参数是char *(暂时不需要知道是什么,马上我们会学习指针的知识,到时就清楚了),c_str()函数就是用于将string转换成char *
运行此程序,不出意外的话,你的电脑的c:/cpp/files/目录下就会多出一个文件 , 里面的内容如下所示:
你也可以写一个程序,请求用户输入自己的名字和年龄,然后你的程序将这些信息写入文件。
我们只需要再处理一个小问题:
假如文件已经存在,那怎么办呢?
如果运行上面的已有程序,那么文件的内容会被删除,然后替换为你写入的内容。但是假如我们想要保留文件本来的内容,只是想在文件末尾追加我们的新内容呢?
不用怕,肯定有办法的。只需要在打开文件的时候添加第二个参数,用于指明文件的打开模式,如下所示:
ofstream mystream("c:/cpp/files/", ios::app);
app是英语append的缩写,表示"追加",也就是说写入的内容不会覆盖原本文件里的内容,而是追加到文件末尾。
我们学习了如何写文件,现在来学习如何读取文件内容吧。你会看到,两种操作是很类似的。
之前我们用了ofstream的对象,那么这次就要用到ifstream的对象了,ifstream是input file stream的缩写。当然也需要测试文件是否顺利被打开。
ifstream mystream("c:/cpp/files/"); //试着打开文件
if(mystream)
{
//可以读取文件
}
else
{
cout "出错: 无法以读的形式打开此文件." endl;
}
没有什么新的难点不是吗?
接下来我们就可以读取文件内容了。
要读取文件内容,有三种不同的方式:
我们分别来学习这三种方式:
第一种方式可以一次读取整一行的内容,将其存储在一个字符串里。举例如下:
string line; // 储存整行内容的字符串变量
getline(mystream, line); //读取整一行,存储到line中
此函数的原理和cin是类似的。
第二种方式,其实你也早就知道了,毕竟聪慧如你嘛。举例如下:
double number;
mystream >> number; //从文件中读取一个浮点数
string word;
mystream >> word; //从文件中读取一个单词
这个方法会读取当前所在的文件位置处的内容和之后的一个空格("词"并不是我们平时说的一个单词,而是以空格来分隔的,假如中间没有空格,那么就是一个词,例如heusyg3这是一个词,但是heu syg3却被认为是两个词,因为中间存在空格)。读取的内容根据变量的类型会被转换成double,int,string,等等。
第三种方式,我们之前没学过,不过也很简单就是了。举例如下:
char a;
(a);
上面的代码读取一个字符,将其存储在char型变量a中。
这个方法可以读取所有字符,不管是字母,空格,回车符,制表符,等等。
还记得在【c++探索之旅】第一部分第五课:简易计算器中,我们学习过cin的用法吗?还记得我们说过在cin>>()吗?因此,这里我们从一个词一个词地读取(用cin>>)转换到一行一行地读取(用getline()),也需要在之间加入ignore()。不过,因为我们这里是在读取文件,(),而要使用ifstream的ignore方法,如下所示:
ifstream mystream("c:/cpp/files/");
string word;
mystream >> word; //读取一个词
(); //改变读取方式
string line;
getline(mystream, line); //读取一整行
很多时候,我们会希望读取整个文件。我们已经学习了如何读取文件,但是还没学习当到达文件结尾时,如何停止。
为了获知我们是否还可以继续读取,可以用getline函数的返回值。getline函数的返回值是一个bool(布尔值),如果等于true,还可以继续读,说明还没到文件末尾;如果等于false,那么说明已经读取了文件的最后一行或者出错了。在false的情况下,就不能再继续读取了。
还记得我们学过的循环吗?只要还没到达文件末尾(getline函数返回是true),我们就继续读取文件。while循环就是最好的选择啦。看如下例子:
#include iostream>
#include fstream>
#include string>
using namespace std;
int main()
{
ifstream file("c:/cpp/files/"); // 尝试打开文件
if(file)
{
//文件顺利打开,可以读取了
string line; //存储读取的一整行的变量
while(getline(file, line)) //只要没到达文件末尾,我们就一直一行一行地读取
{
cout line endl;
//在控制台显示读取的行
//或者随便你拿这一行干什么,由你决定
}
}
else
{
cout "出错: 无法以读的形式打开此文件." endl;
}
return 0;
}
一旦我们读取了这些行,我们就可以非常方便地操作它们了。在上面的例子中,我们只是把读取的每一行显示在控制台中,但是你可以随便怎么用。
这一课的最后,我们来学习几个小技巧,这样文件读写我们就学习得差不多了。
我们已经知道怎么打开一个文件,但还没演示如何关闭文件。倒不是因为我忘记了,而是之前关闭文件显得没有那么必要。一旦我们跳出了文件流声明的区块,打开的文件就会被自动关闭。例如:
void f()
{
ofstream mystream("c:/cpp/files/"); //打开文件
// 操作文件
} //当我们跳出这个函数,文件就自动被关闭了
因此,并不需要做任何操作来显式地关闭文件。
但是,有时候我们想要提前关闭文件,在它被自动关闭前。为了达到这个目的,我们必须"不择手段"... 哦,不是,是使用close函数。例如:
void f()
{
ofstream mystream("c:/cpp/files/"); //打开文件c:/cpp/files/
//使用文件
(); //关闭文件
//自此,我们将不能再往文件里写东西了
}
同样地,我们也可以推迟打开文件。用open函数。例如:
void f()
{
ofstream mystream; //声明文件流,但没有绑定文件
("c:/cpp/files/"); //打开文件c:/cpp/files/
//使用文件
(); //关闭文件
//自此,我们将不能再往文件里写东西了
}
正如你所见,以上的操作都很简单。然而,在大部分时候,没必要使用open和close函数来显示地打开和关闭文件。
我们再来深入一些技术细节,"研究"一下文件的读取是怎么运作的。
你还记得平时用文本编辑器的时候,我们在编辑文本时总会有一个一闪一闪的光标(cursor),指示了我们当前编辑的位置吗?如下图所示:
可以看到,目前光标位于oscar的后面。
在c++中操作文件时,也是同样的原理。有一个游标(cursor)一直指示当前在文件中的位置。
例如,当我们运行这一行的时候:
ifstream file("c:/cpp/files/")
文件c:/cpp/files/会被打开,游标会定位于文件最开始处。
如果之后我们读取第一个词,就会读取到oscar这个词。读取完之后,我们的游标就会位于下一个单词的开始处了,如下图所示:
可以看到,现在游标位于is这第二个词的开始处了。然后我们可以接着读取第二个词,第三个,... 一直到文件结束。
但如果这样的话,我们只能按顺序读取文件,这可太束缚了。我们需要自由,需要飞翔,"在你的心上,自由地飞翔~" (小编,你的药已经准备好了...)
幸好,我们能够在文件中移动,说到移动,那就是移动那个cursor(游标)了。例如,我们可以说"我要移动到距离文件开始处20个字符的地方",或者"我要从当前位置前进32个字符"。这样,我们就可以很方便地读取我们真正想要的内容了。
首先,我们要了解游标目前位于哪里。然后才能正确地移动。
有一个方法可以获知当前我们的游标位于文件的第几个字符处(从文件开始处算起)。不过,对于输入文件流(ifstream)和输出文件流(ofstream),所用的函数不一样,而且名字也有点古怪,我们列在下面:
然而,这两个函数的使用方法完全一样。因此只介绍其中一个就可以了。举例如下:
ofstream file("c:/cpp/files/");
int position = (); //获取当前位置
cout "目前位于文件中的第" position "个字符处." endl;
用于在文件中移动的函数也有两个,成对的,每一个对应一种流的形式:
用法和之前的两个函数类似。
这两个函数接受两个参数:一个是在文件中的位置,另一个是相对文件中的位置的距离数(字符数/字节数)。
(numberofcharacters, position);
对于此函数的position参数,有三种可能的位置:
例如,我想要移动到距离文件开始处10个字符的地方,我会这么做:
(10, ios::beg);
假如我想要移动到距离当前游标所在位置的20个字符处,我会这么做:
(20, ios::cur);
相信你已经理解啦。
这第三个小技巧需要用到前两个。为了获知文件的大小,我们首先移动到文件末尾,然后询问我们所在的位置。你知道怎么做了吗?一起来看看吧:
#include iostream>
#include fstream>
using namespace std;
int main()
{
ifstream file("c:/cpp/files/"); //打开文件
(0, ios::end); //移动到文件末尾
int size;
size = ();
//在文件结尾处调用tellg这个函数,以获得目前位于第几个字符处,因此也就知道了文件的大小
cout "文件的大小是: " size "个字节." endl;
return 0;
}
好了,我们学完了文件读写的大致概念。不过肯定不只于次,还有很多知识点需要慢慢在实践中去探索。
第一部分第十一课预告
今天的课就到这里,一起加油吧!
下一课我们学习:
意味着装13,酒吧里那些营销,那些套路,那些啤酒洗手的,看了就恶心
harbin engineering university 哈尔滨工程大学