前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >文件的输入和输出

文件的输入和输出

作者头像
艰默
发布2023-02-26 11:00:41
1.5K0
发布2023-02-26 11:00:41
举报
文章被收录于专栏:iDoitnow

1. 简单的文件I/O

写入文件

让程序写入文件,其步骤大致为如下:

  1. 创建一个ofstream对象来管理输入流;
  2. 将该对象与特定的文件关联起来;
  3. 用使用cout的方式使用该对象,唯一的区别是输出将进入文件,而不是屏幕。

例子:

代码语言:javascript
复制
//需要包含头文件fstream

ofstream fout;     //#1
fout.open("a.txt");//#2 若a.txt不存在,则会新建一个,若存在,则会清空源文件内容
fout << "hello";   //#3 将hello写入a.txt中

:以默认模式打开文件(即上述方式)进行输出将自动把文件的长度截短为零,这相当于删除已有的内容。具体原因见本文第三节文件模式中的注】

读取文件

读取文件的要求与写入文件相似:

  1. 创建一个ifstream对象来管理输入流;
  2. 将该对象与特定的文件关联起来;
  3. 以使用cin的方式使用该对象。

例子:

代码语言:javascript
复制
//需要包含头文件fstream

ifstream fin;     //#1
fin.open("a.txt");//#2 
char ch;
fin >> ch;        //#3 读取一个字符放入ch

:当输入和输出流对象过期(如程序终止)时,到文件的连接将自动关闭。另外,也可以使用close()方法来显式地关闭到文件的连接。关闭这样的连接并不会删除流,而只是断开流到文件的连接。然而,流管理装置仍被保留。】

流状态检查

C++文件流类从ios_base类那里继承了一个流状态成员。检查文件是否成功打开的常见方式如下:

代码语言:javascript
复制
ifstream fin;
fin.open(argv[file]);

if (fin.fail()){...} //判断文件打开是否成功
if (!fin.good()){...} //判断文件打开是否成功
if (!fin){...} //判断文件打开是否成功

//is_open()能够检测到这种错误以及good()能够检测到的错误。然而,老式C++实现没有is_open( )。
if (!fin.is_open()){...} //判断文件打开是否成功

2. 命令行处理技术

文件处理程序通常使用命令行参数来指定文件。例如:

代码语言:javascript
复制
exc a.txt b.txt

exc为程序可执行文件名,a.txtb.txt为程序exc执行过程中要使用到的文件。要实现上述功能,则程序的主函数应该写为:

代码语言:javascript
复制
int main(int argc, char* argv[])

argc为命令行中的参数个数,其中包括命令名本身。argv变量为一个指针,它指向一个指向char的指针。这过于抽象,但可以将argv看作一个指针数组,其中的指针指向命令行参数,argv[0]是一个指针,指向存储第一个命令行参数的字符串的第一个字符,依此类推。也就是说,argv[0]是命令行中的第一个字符串,依此类推。因此上面的例子中:argc为3,argv[0]excargv[1]a.txtargv[2]b.txt

3. 文件模式

文件模式描述的是文件将被如何使用:读、写、追加等。将流与文件关联时(无论是使用文件名初始化文件流对象,还是使用open()方法),都可以提供指定文件模式的第二个参数:

代码语言:javascript
复制
ifstream fin("banjo", mode1); // mode1为文件模式
ofstream fout();
fout.open("harp", mode2); // mode2为文件模式

文件模式的常量有:

常量

含义

ios_base::in

打开文件,以便读取

ios_base::out

打开文件,以便写入

ios_base::ate

打开文件,并移到文件尾

ios_base::app

追加到文件尾

ios_base::trunc

如果文件存在,则截短文件

ios_base::binary

二进制文件

ifstream open()方法和构造函数用ios_base::in(打开文件以读取)作为模式参数的默认值,而ofstream open()方法和构造函数用ios_base::out | ios_base::trunc(打开文件,以读取并截短文件,也就是说,其以前的内容将被删除)作为默认值。位运算符OR(|)用于将两个位值合并成一个可用于设置两个位的值。fstream类不提供默认的模式值,因此在创建这种类的对象时,必须显式地提供模式。】

如果要保留文件内容,并在文件尾添加(追加)新信息,则可以使用ios_base::app模式:

代码语言:javascript
复制
ofstream fout("bagels", ios_base::out | ios_base::app);//使用|运算符来合并模式,启用模式out和app

老式C++实现之间可能有一些差异。例如,有些实现允许省略前一例子中的ios_base::out,有些则不允许。如果不使用默认模式,则最安全的方法是显式地提供所有的模式元素。

要以二进制格式(而不是文本格式)存储数据,可以使用ofstream对象的write()成员函数。该方法将内存中指定数目的字节复制到文件中。若从二进制文件读取数据,可以使用ifstream对象的read( )成员函数。该方法从文件中内容复制到目标结构中。这两者的对应的使用方法如下:

代码语言:javascript
复制
const int LIM = 20;
struct planet
{
    char name[LIM]; // name of planet
    double population; // its population
    double g; // its acceleration of gravity
};
planet pl;
planet p2;

//写入
//ofstream fout("planets.dat", ios_base:: out | ios_base::app);
//fout << pl.name << " " << pl.population << " " << pl.g << "\n";
ofstream fout("planets.dat",
              ios_base:: out | ios_base::app | ios_base::binary);
fout.write( (char *) &pl, sizeof(pl));

//读取
ifstream fin("planets.dat", ios_base::in | ios_base::binary);
fin.read((char *) &p2, sizeof(p2));

4. 随机存取

随机存取指的是直接移动(不是依次移动)到文件的任何位置。要实现读/写的效果,需要同时使用in模式和out模式将得到读/写模式,要使用|运算符来组合模式。因此,需要使用下面的语句:

代码语言:javascript
复制
fstream finout;//fstream类是从iostream类派生而来的,而后者基于istream和ostream两个类,因此它继承了它们的方法。它还继承了两个缓冲区,一个用于输入,一个用于输出,并能同步化这两个缓冲区的处理。
finout.open(file, ios_base::in | ios_base::out | ios_base::binary);

接下来,需要一种在文件中移动的方式。fstream类为此继承了两个方法:seekg()seekp(),前者将输入指针移到指定的文件位置,后者将输出指针移到指定的文件位置(实际上,由于fstream类使用缓冲区来存储中间数据,因此指针指向的是缓冲区中的位置,而不是实际的文件)。也可以将seekg()用于ifstream对象,将seekp()用于oftream对象。

seekg()seekp()的原型及使用方法如下:

代码语言:javascript
复制
//seekg()
istream & seekg(streamoff, ios_base::seekdir);//第一个原型定位到离第二个参数指定的文件位置特定距离(单位为字节)的位置;streamoff值被用来度量相对于文件特定位置的偏移量(单位为字节)。
istream & seekg(streampos);//第二个原型定位到离文件开头特定距离(单位为字节)的位置。streampos对应的是距离(单位为字节)。

//seek_dir参数是ios_base类中定义的另一种整型,有3个可能的值:
//常量ios_base::beg指相对于文件开始处的偏移量;
//常量ios_base::cur指相对于当前位置的偏移量;
//常量ios_base::end指相对于文件尾的偏移量。
fin.seekg(30, ios_base::beg); //将读取位置设置为从文件开头开始的第31个字节(字节编号为30)
fin.seekg(-1, ios_base::cur); //将读取位置设置为从当前位置后退1个字节
fin.seekg(0, ios_base::end); //将读取位置设置为从文件尾0个字节的位置

fin.seekg(112); //第一个字节的编号为0。因此该语句将读取位置设置为第112个字节,也就是文件中的第113个字节



//seekp()
ostream & seekp(streamoff offset,seek_dir origin); 
ostream & seekp (streampos pos);

fout.seekp(30, ios_base::beg); //将写入位置设置为从文件开头开始的第31个字节(字节编号为30)
fout.seekp(-1, ios_base::cur); //将写入位置设置为从当前位置后退1个字节
fout.seekp(0, ios_base::end); //将写入位置设置为从文件尾0个字节的位置

fout.seekp(112); //第一个字节的编号为0。因此该语句将写入位置设置为编号为112的字节,也就是文件中的第113个字节

:如果要检查文件指针的当前位置,则对于输入流,可以使用tellg()方法,对于输出流,可以使用tellp()方法。它们都返回一个表示当前位置的streampos值(以字节为单位,从文件开始处算起)。】

seekg()seekp()函数提供对文件的随机存取。这些类方法使得能够将文件指针放置到相对于文件开头、文件尾和当前位置的某个位置。tellg()tellp()方法报告当前的文件位置。

参考文献 C++ Primer Plus(第六版) - 第17章 输入、输出和文件

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-02-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 iDoitnow 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 简单的文件I/O
  • 2. 命令行处理技术
  • 3. 文件模式
  • 4. 随机存取
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档