使用文件输入/输出

C ++提供了以下类来执行字符/来自文件的输出和输入: 

  • ofstream Stream类文件上写
  • ifstream Stream类从文件中读取
  • fstream Stream类读取和从/写入文件。

这些类被直接或间接地从类派生 istreamostream。我们已经使用的对象,其类型为这些类: cin是类的一个对象 istream,并 cout为类的一个对象 ostream。因此,我们已经使用被涉及到我们的文件流类已经过。而事实上,我们可以用我们的文件流,我们已经习惯了用同样的方法 cin,并 cout与我们有与物理文件这些流关联的唯一区别。让我们看一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
// basic file operations
#include <iostream>
#include <fstream>
using namespace std;

int main () {
  ofstream myfile;
  myfile.open ("example.txt");
  myfile << "Writing this to a file.\n";
  myfile.close();
  return 0;
}
[文件example.txt文件]
写这篇到一个文件中。


此代码创建一个名为文件 example.txt并插入一个句子到它在我们习惯用做同样的方式 cout,但使用文件流 myfile来代替。

但是,让我们走一步看一步:

打开文件

通常这些类中的一个的对象上执行的第一个操作是其关联到一个真正的文件。此过程被称为到 打开一个文件。一个打开的文件是由一个程序内表示 (即,这些类中的一个的目的;在前面的例子中,这是 myfile),这流对象上执行的任何输入或输出操作将被应用到相关联的物理文件它。

为了打开与我们使用它的成员函数流对象的文件 open: 如果是要打开表示文件名的字符串,并且是具有以下标志的组合可选参数:

open (filename, mode);

filename mode

ios::in打开输入操作。
ios::out打开输出操作。
ios::binary以二进制方式打开。
ios::ate设定在该文件的末尾的初始位置。
如果未设置该标志时,初始位置是文件的开头。
ios::app所有输出操作是在该文件的结束时执行,追加的内容,以该文件的当前内容。
ios::trunc如果该文件被打开输出操作和它已经存在,其以前的内容被删除,并用新的替换。

所有这些标志可以使用位运算符OR(组合 |)。例如,如果我们要打开的文件 example.bin以二进制模式添加数据,我们可以通过下面的调用成员函数做到这一点 open

1
2
ofstream myfile;
myfile.open ("example.bin", ios::out | ios::app | ios::binary); 
 


每个 open类别成员函数 ofstreamifstream并且 fstream具有用于如果该文件没有第二个参数开了默认模式:

默认模式参数
ofstreamIOS ::出来
ifstreamIOS ::在
fstreamIOS ::在| IOS ::出来

ifstreamofstream类, ios::in以及 ios::out自动和分别假定,即使不包括它们一模式被作为第二个参数,以传递的 open成员函数(标志被组合)。

对于 fstream,如果调用函数时不指定mode参数的任何值默认值仅适用。如果函数调用中参数的默认模式覆盖的任何值,而不是合并。

在打开的文件流 二进制模式独立地进行的任何格式的考虑输入和输出操作。非二进制文件被称为 文本文件,并且由于一些特殊的字符(如换行和回车符)的格式可能会出现一些翻译。

因为这是在文件流执行第一任务通常是打开一个文件,这三个类包括一个构造自动调用 open成员函数和具有完全相同的参数,此成员。因此,我们也可以宣布先前的 myfile对象,并通过书面形式在我们前面的例子进行同样的操作开启:

 
ofstream myfile ("example.bin", ios::out | ios::app | ios::binary);
 


结合对象的建设和开放流在一个声明。两种形式打开文件是有效的和等同。

要检查文件流成功打开一个文件,你可以通过调用成员做到这一点 is_open。该成员函数返回 bool的值 true在确实流对象是一个开放的文件,或相关的情况下 false,否则:

 
if (myfile.is_open()) { /* ok, proceed with output */ }
 


关闭文件

当我们对一个文件提供了输入和输出操作完成,使得操作系统通知和其资源再次变为可用,我们将其关闭。为此,我们称之为流的成员函数 close。该成员函数将刷新缓冲区关联,并关闭文件:

 
myfile.close();
 


一旦该成员函数被调用时,该流对象可被重新用于打开另一个文件,并将该文件再次可用到其它进程打开。

在这同时仍然以开放的文件关联的对象被销毁的情况下,析构函数自动调用成员函数 close

文本文件

文本文件流是其中的 ios::binary,不包含在它们的开口模式标志。这些文件被设计用于存储文本,因此是从/向这些输入或输出的所有值可以遭受一些格式转换,其不必对应于它们的字面二进制值。

文本文件写入操作在我们与操作的相同的方式进行 cout

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// writing on a text file
#include <iostream>
#include <fstream>
using namespace std;

int main () {
  ofstream myfile ("example.txt");
  if (myfile.is_open())
  {
    myfile << "This is a line.\n";
    myfile << "This is another line.\n";
    myfile.close();
  }
  else cout << "Unable to open file";
  return 0;
}
[文件example.txt文件]
这是一条线。
这是另一条线。


从文件中读取,也可以在我们与做了同样的方式执行 cin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// reading a text file
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main () {
  string line;
  ifstream myfile ("example.txt");
  if (myfile.is_open())
  {
    while ( getline (myfile,line) )
    {
      cout << line << '\n';
    }
    myfile.close();
  }

  else cout << "Unable to open file"; 

  return 0;
}
这是一条线。
这是另一条线。  


最后一个例子读取文本文件,并打印出其屏幕上的内容。我们创建了一个while循环逐行读取文件中的行,使用 函数getline。返回的值 函数getline是流对象本身,其中,当作为布尔表达式计算(如在此同时,回路)的引用是 true如果流是准备更多的操作,以及 false如果该文件的任一端已达到或如果一些其他错误发生。

检查状态标志

下面的成员函数存在检查流(所有这些返回的特定状态 bool值):

bad()
返回 true如果一个读取或写入操作失败。例如,在我们试图写入一个文件未打开撰写或如果我们尝试写设备的情况下没有剩余空间。
fail()
返回 true在同一个案件 bad(),而且在一个格式错误发生,当一个字母字符,当我们试图读取一个整数提取等的情况下。
eof()
返回 true如果打开一个文件进行读取已走到了尽头。
good()
这是最通用的状态标志:它返回 false在其调用任何先前的功能将返回相同的情况下 true。请注意, goodbad(没有确切的对立面 good一次检查,更多的国家标志)。

成员函数 clear()可以用来重置状态标志。

get和put流定位

所有的I / O流对象内部保持-AT least-一个内部的位置:

ifstream一样 istream,保持内部 获得位置与元素的位置,在接下来的输入操作被读取。

ofstream一样 ostream,保持内部 放位置与其中一个元素已被写入的位置。

最后 fstream,保持两者的 获取放的位置,像 iostream

这些内部流位置指向在其中执行的下一个读或写操作的流中的位置。这些位置可以观察并使用下面的成员函数修改:

所以tellg()和tellp()
不带参数的这两个成员函数返回成员类型的值 streampos,这是代表当前一种 获得位置(在的情况下 tellg)或 放的位置(在的情况下 tellp)。

seekg()和seekp()
这些功能允许改变位置 GET放位置。这两个函数重载两个不同的原型。第一种形式是: 使用这种原型,流指针被改变为绝对位置(从文件的开头算起)。类型此参数是,这是由函数返回的同一类型和。 另一种形式为这些功能是: 使用该原型中, 获取放的位置被设定为抵消相对于由参数确定某些特定点处的值。是类型。并且是类型的,这是一个 枚举类型确定从哪里抵消从计数的,并且,可以采取以下任意值的点:

seekg ( position );
seekp ( position );

position streampos tellg tellp



seekg ( offset, direction );
seekp ( offset, direction );

direction offset streamoff direction seekdir

ios::beg从该流的开始的偏移计数
ios::cur从当前位置偏移计数
ios::end从流的末端偏移计数

下面的示例使用我们刚才看到的,以获得一个文件的大小的构件的功能: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// obtaining file size
#include <iostream>
#include <fstream>
using namespace std;

int main () {
  streampos begin,end;
  ifstream myfile ("example.bin", ios::binary);
  begin = myfile.tellg();
  myfile.seekg (0, ios::end);
  end = myfile.tellg();
  myfile.close();
  cout << "size is: " << (end-begin) << " bytes.\n";
  return 0;
}
尺寸是:40个字节。


请注意,我们一直使用的变量的类型 beginend

 
streampos size;
 


streampos是用于缓冲和文件定位特定的类型和是由返回的类型 file.tellg()。这种类型的值可以安全地从同一类型的其它值中减去,并且也可以被转换为整数型大到足以包含的文件的大小。

这些流定位功能使用两种特定类型: streamposstreamoff。这些类型也被定义为成员类型的流类的:

类型会员类型描述
streamposios::pos_type定义fpos<mbstate_t>
它可以从被转换到/ streamoff并且可以增加或减少这些类型的值。
streamoffios::off_type它是基本积分类型(如之一的别名intlong long)。

上述各构件的类型之一是它的非会员等效的别名(它们是完全相同的类型)。不要紧使用哪一个。会员类型是更通用的,因为他们是所有流对象(即使在利用外来类型的字符流)相同,但非会员类型广泛应用于现有的代码由于历史的原因。

二进制文件

对二进制文件,读,写数据的提取和插入操作符( <<>>)和功能一样 getline是没有效率的,因为我们不需要格式化的任何数据和数据很可能在线路未格式化。

文件流包括专门设计用于读取和写入数据的顺序二进制两个成员函数: writeread。第一个( write)是一个成员函数 ostream(由继承 ofstream)。而且 read是一个成员函数 istream(通过继承 ifstream)。类的对象 fstream兼得。他们的原型是:

写(memory_block,大小); 
阅读(memory_block,大小); 

其中, memory_block是类型 char*(指针 char),并代表所读出的数据元素被存储或从那里采取将要写入的数据元素字节数组的地址。的 size参数是一个整数值,指定要被读出或从/到存储块写入的字符的数目。

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
// reading an entire binary file
#include <iostream>
#include <fstream>
using namespace std;

int main () {
  streampos size;
  char * memblock;

  ifstream file ("example.bin", ios::in|ios::binary|ios::ate);
  if (file.is_open())
  {
    size = file.tellg();
    memblock = new char [size];
    file.seekg (0, ios::beg);
    file.read (memblock, size);
    file.close();

    cout << "the entire file content is in memory";

    delete[] memblock;
  }
  else cout << "Unable to open file";
  return 0;
}
整个文件内容是在存储器


在本实施例中,整个文件被读取并存储在一个存储器块中。让我们来看看如何做到这一点:

首先,文件与开放的 ios::ate标志,这意味着GET指针将被定位在文件的结尾。这样,当我们打电话给成员 tellg(),我们将直接获取该文件的大小。

一旦我们获得文件的大小,我们要求一个内存块大到足以容纳整个文件的分配:

 
memblock = new char[size];
 


紧接着,我们开始设置 获得位置在文件(记得我们开了这个指针末端的文件)的开始,那么我们读取整个文件,最后关闭它:

1
2
3
file.seekg (0, ios::beg);
file.read (memblock, size);
file.close();
 


在这一点上,我们可以从文件中获得的数据进行操作。但是,我们的程序只是简单地宣布,该文件的内容是在内存中,然后完成。

缓冲区和同步

当我们用文件流进行操作,这些相关联的类型的内部缓冲器的对象 streambuf。这个缓冲对象可代表一个存储器块充当流和物理文件之间的中介。例如,对于一个 ofstream中,每个成员函数的时间 put(其写入单个字符)被调用时,该字符可在这个中间缓冲器,而不是被直接写入到与该流相关联的物理文件插入。

操作系统也可以定义缓冲的其它层用于读取和写入文件。

当缓冲器被刷新,所有包含在其中的数据被写入到物理介质(如果它是一个输出流)。这个过程被称为 同步,并在任何有下列情形之一发生:

  • 当文件被关闭:关闭一个文件之前,尚未被刷新所有缓冲区同步,并且所有未决数据被写入或读出的物理介质。
  • 当缓冲区已满:缓冲器具有一定的规模。当缓冲区已满,自动同步。
  • 明确,具有操控:当某些操纵器上使用的数据流,显式同步发生。这些机器人是:flushendl
  • 明确的,具有成员函数的sync():调用流的成员函数sync()会立即同步。该函数返回一个int等于值-1如果流不具有相关联的缓冲器或故障的情况下。否则(如果流缓存被成功同步)返回0
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值