在写代码的过程中。我们最常做的事就是io操作,不管是对控制台,还是文件。但一段时间不写代码就忘了,这里理一下C++标准I/O库的详细类和操作。

C++的标准I/O库包含我们常常使用的iostream,fstream。以及不太常常使用的stringstream。前两者是对控制台和文件的I/O操作,stringstream则能够使用I/O操作对内存中的数据进行格式化操作。

C++的标准I/O操作相对与C来说,更加的简明,安全,但运行效率会有所下降。



标准I/O库类继承体系                                                                    

对于编程语言来说,在概念上,从控制终端、磁盘文件以及内存中读取数据都应该不影响I/O操作。C++为了解决支持不同设备的字符流。通过面向对象的思想(废话了,你要不用这个思想,你还是什么C++)。通过继承来实现一组类,分别处理控制终端、磁盘文件,以及内存数据的I/O操作,下图是引用cplusplus官网关于输入输出流类继承体系的关系图,自己画了一下,例如以下:

由上图能够知道,I/O操作的基类是ios_base,各个类的用途例如以下:

  • <iostream>
  • istream    从流中读取数据
  • ostream   向流中写数据
  • iostream  对流进行读写操作。派生于istream和ostream
  • <fstream>
  • ifstream    从文件里读取数据。派生于istream
  • ofstream   向文件里写数据,派生于ostream
  • fstream     读写文件, 派生于iostream
  • <sstream>
  • istringstream    读取string对象。派生于istream
  • ostringstream   写string对象。派生于ostream
  • stringstream     读写string对象,派生于iostream

C++标准对于I/O体系,定义了主要的流格式标志(hex, dec,等),文件打开模式(in, out, bin等),流的状态标志(failbit等)。以及相关的函数等,例如以下在linux 下/usr/include/c++/4.6/bits/ios_base.h中关于这些标志的枚举定义:

  • 流格式标志
enum _Ios_Fmtflags
{
_S_boolalpha = 1L << 0,
_S_dec = 1L << 1,
_S_fixed = 1L << 2,
_S_hex = 1L << 3,
_S_internal = 1L << 4,
_S_left = 1L << 5,
_S_oct = 1L << 6,
_S_right = 1L << 7,
_S_scientific = 1L << 8,
_S_showbase = 1L << 9,
_S_showpoint = 1L << 10,
_S_showpos = 1L << 11,
_S_skipws = 1L << 12,
_S_unitbuf = 1L << 13,
_S_uppercase = 1L << 14,
_S_adjustfield = _S_left | _S_right | _S_internal,
_S_basefield = _S_dec | _S_oct | _S_hex,
_S_floatfield = _S_scientific | _S_fixed,
_S_ios_fmtflags_end = 1L << 16
};
  • 文件打开模式
enum _Ios_Openmode
{
_S_app = 1L << 0,
_S_ate = 1L << 1,
_S_bin = 1L << 2,
_S_in = 1L << 3,
_S_out = 1L << 4,
_S_trunc = 1L << 5,
_S_ios_openmode_end = 1L << 16
};
  • 流的状态标志
 enum _Ios_Iostate
{
_S_goodbit = 0,
_S_badbit = 1L << 0,
_S_eofbit = 1L << 1,
_S_failbit = 1L << 2,
_S_ios_iostate_end = 1L << 16
};

I/O流的状态                                                                                   

为了更好地管理I/O操作。标准定义了一系列条件状态标志和函数,用来管理流对象。比方说是否可用,以及出现的错误。

对于流的状态标志是在ios_base类中进行定义的。所以流的状态标志管理适用于终端、文件、string流对象。流的状态定义为:ios_base::iostate,详细有哪些值在ios_base中有定义,例如以下:

    typedef _Ios_Iostate iostate;
static const iostate badbit = _S_badbit; //流被破坏 (流本身的问题)
static const iostate eofbit = _S_eofbit; //流已到结尾
static const iostate failbit = _S_failbit; //I/O失败(操作本身上的逻辑问题)
static const iostate goodbit = _S_goodbit; //好流...正常

为了管理上述的状态标志,标准在ios类中提供了下面函数来进行处理:

iostate  rdstate() const                     //返回流的条件状态
void clear(iostate __state = goodbit); //设置流的条件状态,默认设置为正常
void setstate(iostate __state); //设置流的状态,和clear的差别:不会清除其它标志
bool good() const //流的是否正常
bool eof() const //流是否到结尾
bool fail() const //流是否I/O失败
bool bad() const //流是否被破坏

能够通过以下代码简单进行状态标志的測试:

#include <iostream>

using std::cout;
using std::cin;
using std::endl; int main()
{
int a; cin>>a;
cout<<"goodbit: "<<cin.good()<<" eofbit: "<<cin.eof()<<" failbit: "<<cin.fail()<<" badbit: "<<cin.bad()<<endl; cin>>a;
cout<<"goodbit: "<<cin.good()<<" eofbit: "<<cin.eof()<<" failbit: "<<cin.fail()<<" badbit: "<<cin.bad()<<endl;
}

输入1 a后显演示样例如以下:

1
goodbit: 1 eofbit: 0 failbit: 0 badbit: 0
a
goodbit: 0 eofbit: 0 failbit: 1 badbit: 0

由上可知非法输入会导致I/O失败,failbit流标志生效。



文件I/O操作                                                                                  

C++提供了ifstream和ofstream类负责文件I/O的读和写操作。类fstream负责文件的读写。继承关系文章开头已说明。

前面说了,在ios_base基类中定义了文件打开模式,

typedef _Ios_Openmode openmode;

/// Seek to end before each write.
static const openmode app = _S_app; /// Open and seek to end immediately after opening.
static const openmode ate = _S_ate; /// Perform input and output in binary mode (as opposed to text mode).
static const openmode binary = _S_bin; /// Open for input. Default for @c ifstream and fstream.
static const openmode in = _S_in; /// Open for output. Default for @c ofstream and fstream.
static const openmode out = _S_out; /// Open for input. Default for @c ofstream.
static const openmode trunc = _S_trunc;

详细含义例如以下:

  • ios_base::in    仅仅读打开
  • ios_base::out    仅仅写打开
  • ios_base::app    每次写之前移到文件尾
  • ios_base::ate    打开文件后立马定位到文件尾
  • ios_base::trunc    打开文件并清空文件流
  • ios_base::binary    以二进制模式进行读写操作

以ifstream方式打开文件,默认打开方式为in。以ofstream方式打开,默认打开方式为out | trunc。fstream是默认以in | out方式打开。假设要以ofstream打开文件。且同一时候保存文件的数据。仅仅能通过显示的指定app打开模式。

例如以下是fstream头文件里的open函数原型:

ifstream
void open(const char* __s, ios_base::openmode __mode = ios_base::in) ofstream
void open(const char* __s, ios_base::openmode __mode = ios_base::out | ios_base::trunc) fstream
void open(const char* __s, ios_base::openmode __mode = ios_base::in | ios_base::out)

假设fstream打开方式是out,也会清空文件里数据。

当文件以out方式打开(不包括in模式)时,假设文件不存在,会创建一个新文件。

  • 输入输出操作符

istream,ostream类中都定义了用于输入输出的算法提取器(Arithmetic Extractor):'>>'和‘<<’操作符,能够提取内置数据类型的数据,比如,输入操作符>>用于从流缓冲区streambuf中提取数据。并输出到特定类型的变量中,比如istream头文件里详细定义例如以下:

//类内定义的,用于提取
__istream_type& operator>>(bool& __n);
__istream_type& operator>>(short& __n);
__istream_type& operator>>(unsigned short& __n);
__istream_type& operator>>(int& __n);
__istream_type& operator>>(unsigned int& __n);
__istream_type& operator>>(long& __n);
__istream_type& operator>>(unsigned long& __n);
__istream_type& operator>>(long long& __n);
__istream_type& operator>>(unsigned long long& __n);
__istream_type& operator>>(float& __f)
__istream_type& operator>>(double& __f)
__istream_type& operator>>(long double& __f)
__istream_type& operator>>(void*& __p) //类外定义的,用于提取字符
template<class _Traits>
inline basic_istream<char, _Traits>&
operator>>(basic_istream<char, _Traits>& __in, unsigned char& __c); template<class _Traits>
inline basic_istream<char, _Traits>&
operator>>(basic_istream<char, _Traits>& __in, signed char& __c); template<class _Traits>
inline basic_istream<char, _Traits>&
operator>>(basic_istream<char, _Traits>& __in, unsigned char* __s); template<class _Traits>
inline basic_istream<char, _Traits>&
operator>>(basic_istream<char, _Traits>& __in, signed char* __s); //string类中对输入输出operator的重载,使其能支持string类型的输入输出
template<typename _CharT, typename _Traits, typename _Alloc>
basic_istream<_CharT, _Traits>&
operator>>(basic_istream<_CharT, _Traits>& __is,
       basic_string<_CharT, _Traits, _Alloc>& __str); template<typename _CharT, typename _Traits, typename _Alloc>
inline basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>& __os,
       const basic_string<_CharT, _Traits, _Alloc>& __str)

因为ifstream和ofstream派生于istream和ostream,所以fstream相同支持对文件流filebuf的输入输出操作。比例如以下例通过输入输出操作符读取文件里的数据:

#include <iostream>
#include <fstream>
#include <string> using namespace std; int main ()
{
string fileName = "test.txt";
ofstream outOpt(fileName.c_str(), ios_base::out | ios_base::trunc);
if(!outOpt)
{
cout<<fileName<<" open failed..."<<endl;
return -1;
} outOpt<<"1 2 3 test text";
outOpt.close(); int a[3];
string b[2]; ifstream inOpt(fileName.c_str());
inOpt>>a[0]>>a[1]>>a[2]; //以空白符为分隔,从文件缓冲区中读取三个整数
inOpt>>b[0]>>b[1]; //以空白符为分隔,从文件缓冲区读取两个string数据(string类型对operator <<进行类重载,所以能够支持该操作) cout<<a[0]<<' '<<a[1]<<' '<<a[2]<<endl;
cout<<b[0]<<' '<<b[1]<<endl;
inOpt.close(); return 0;
}
  • getline操作

在文件I/O的过程中,我们常常要处理的是按行对数据进行分析处理。istream类内定义了getline成员函数支持以特定的size或delimiter(默觉得换行符)来提取定长或以特定分隔符分开的数据。相同,string头文件里也提供了getline全局函数,支持从istream类中。以特定的size或delimiter(默觉得换行符)来提取数据。定义例如以下:

//istream类内定义,提供从输入流中读取一行数据到char*中
__istream_type&
getline(char_type* __s, streamsize __n, char_type __delim); //delim默觉得换行 //string头文件定义(实际在basic_string.h中), 提供从输入流中读取一行数据到string中
template<typename _CharT, typename _Traits, typename _Alloc>
basic_istream<_CharT, _Traits>&
getline(basic_istream<_CharT, _Traits>& __is,
basic_string<_CharT, _Traits, _Alloc>& __str, _CharT __delim); //delim默觉得换行

使用例如以下:

#include <iostream>
#include <fstream> #include <string> using namespace std; int main()
{
ifstream inFile("test.txt");
if(!inFile)
{
cout<<"open test.txt failed..."<<endl;
return -1;
} char str1[256] = "";
inFile.getline(str1, 255, '\n'); string str2;
getline(inFile, str2); cout<<str1<<endl;
cout<<str2<<endl;
}
  • 获取文件的所有内容的seekg和tellg

为了对文件高效的操作时常要用到文件流的定位功能。在ios_base类中。定义了例如以下的成员,

typedef _Ios_Seekdir seekdir;
static const seekdir beg = _S_beg; //文件流开头
static const seekdir cur = _S_cur; //当前所在文件流的位置
static const seekdir end = _S_end; //文件流尾部

在istream中定义了tellg和seekg。ostream中定义了tellp和seekp,分别用来获取当前操作所在文件流的位置和进行文件流的操作的定位。例如以下是通过seek操作来读取整个文件的内容到内存中:

#include <iostream>
#include <fstream> int main ()
{
std::ifstream is ("test.txt", std::ios_base::binary);
if (is)
{
//获取文件的大小
is.seekg (0, std::ios_base::end); //定位到文件结尾
int length = is.tellg(); //获取当前所在文件流的位置,因为已经定位文件结尾,所以是获取文件流大小
is.seekg (0, is.beg); //又一次将pos定位到文件流開始 char * buffer = new char [length];
is.read (buffer,length);
is.close(); // 输出到屏幕
std::cout.write (buffer,length); delete[] buffer;
} return 0;
}

内存数据的 I/O操作                                                                         

C++ I/O标准库支持内存数据的I/O的操作,在sstream头文件里定义了 istringstream,ostringstream。stringstream,仅仅须要将流与内存string对象绑定,就能够进行I/O操作。上面三个I/O类分别用来读取内存string对象到指定对象中,将指定对象中的数据写写入string对象。stringstream可用来读写string对象。

在上面I/O文件操作一节已经说了在istream和ostream中定义的标准输入输出操作,由派生关系可知,对于istringstream,ostringstream相同能够进行标准输入输出操作,对stringstream的stringbuf进行操作(与iostream的streambuf,fstream的filebuf类似,这里暂不介绍)。对于stringstream类经常使用的操作例如以下:

stringstream ss(mystr)//创建ss对象,stream流中存放string类型的mystr的数据;
ss.str() //返回ss流中的数据,返回类型为string类型
ss.str(mystr) //设置ss流中数据为mystr的内容

详细使用例如以下:

#include <iostream>
#include <sstream>
#include <string> using namespace std; int main()
{
istringstream istream;
istream.str("1 2 3 hello"); int a, b, c;
string str1;
istream>>a>>b>>c>>str1; //从流中读取数据到对象中(以空白符为切割符)
cout<<a<<' '<<b<<' '<<c<<' '<<str1<<endl; ostringstream ostream;
ostream<<a<<' '<<b<<' '<<c<<' '<<str1; //向流中写数据 string out = ostream.str();
cout<<out<<endl;
}

C++标准I/O库:iostream, fstream, sstringstream的更多相关文章

  1. 标准I/O库(详解)(Standard I/O Library)

    文章转自:https://www.cnblogs.com/kingcat/archive/2012/05/09/2491847.html 自己在学习中,对此原文的基础之上进行补充. 什么是缓冲区 缓冲 ...

  2. Linux C 文件操作,系统调用 -- open()、read() 和 标准I/O库 -- fopen()、fread()

    函数汇总: open().write().read().close() fopen().fwrite().fread().fclose() 一.什么是文件 在讲述文件操作之前,我们首先要知道什么是文件 ...

  3. Xcode6.1标准Framework静态库制作方法。工程转Framework,静态库加xib和图片。完美解决方案。

    http://www.cocoachina.com/bbs/read.php?tid-282490.html Xcode6.1标准Framework静态库制作方法.工程转Framework,静态库加x ...

  4. UNIX环境高级编程笔记之标准I/O库

    一.总结 文件I/O一章讲了不带缓冲的I/O,本章讲的是带缓冲的I/O.不带缓冲针对的是内核的系统调用,而带缓冲针对的是用户空间的标准库函数,是基于带缓冲的I/O实现的.不带缓冲的I/O通过文件描述符 ...

  5. 标准I/O库之缓冲

    标准I/O库提供缓冲的目的是尽可能减少使用read和write调用的次数.它也对每个I/O流自动地进行缓冲管理,从而避免了应用程序需要考虑这一点所带来的麻烦. 标准I/O提供了三种类型的缓冲: (1) ...

  6. 标准I/O库之流和FILE对象

    对于标准I/O库,它们的操作是围绕流(stream)进行的.当用标准I/O库打开或创建一个文件时,我们已使一个流与一个文件相关联. 对于ASCII字符集,一个字符用一个字节表示.对于国际字符集,一个字 ...

  7. 标准I/O库之临时文件

    ISO C标准I/O库提供了两个函数以帮助创建临时文件. #include <stdio.h> char *tmpnam( char *ptr ); 返回值:指向唯一路径名的指针 FILE ...

  8. 标准I/O库之标准I/O的效率

    程序清单5-1 用getc和putc将标准输入复制到标准输出 #include "apue.h" int main( void ) { int c; while(( c = get ...

  9. 标准I/O库之读和写流

    一旦打开了流,则可在三种不同类型的非格式化I/O中进行选择,对其进行读.写操作: (1)每次一个字符的I/O.一次读或写一个字符,如果流是带缓冲的,则标准I/O会处理所有缓冲. (2)每次一行的I/O ...

随机推荐

  1. vue 中scroll事件不触发问题

    在vue项目中需要监听滚动条滚动的位置,结果写了scroll监听事件就是不生效,最后查资料发现是页面有样式设置了over-flow:scroll,去掉之后完美解决.(页面样式中存在over-flow: ...

  2. 浅谈Link-Cut Tree(LCT)

    0XFF 前言&概念 Link-Cut Tree 是一种用来维护动态森林连通性的数据结构,适用于动态树问题.它采用类似树链剖分的轻重边路径剖分,把树边分为实边和虚边,并用 Splay 来维护每 ...

  3. 剑指Offer(书):数值的整数次方

    题目:给定一个double类型的浮点数base和int类型的整数exponent.求base的exponent次方. 分析: * 要注意以下几点:* 1.幂为负数时,base不能为0,不然求的时候是对 ...

  4. 未能加载文件或程序集“System.ServiceModel, Version=2.0.5.0, ...”解决方法

    未能加载文件或程序集“System.ServiceModel, Version=2.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35”或它 ...

  5. 大数据学习——JAVA采集程序

    1 需求 从外部购买数据,数据提供方会实时将数据推送到6台FTP服务器上,我方部署6台接口采集机来对接采集数据,并上传到HDFS中 提供商在FTP上生成数据的规则是以小时为单位建立文件夹(2016-0 ...

  6. 一个监控oracle数据库某个字段值变化并发送邮件报警的脚本

    talk is cheap,here is the code: #!/bin/sh export ORACLE_HOME=/u01/app/oracle/product//client_1/ expo ...

  7. xtu summer individual 1 C - Design the city

    C - Design the city Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu D ...

  8. python3--算法基础:二分查找/折半查找

    算法基础:二分查找/折半查找 #!/usr/bin/env python # -*- coding:utf-8 -*- # 算法基础:二分查找/折半查找 def binarySearch(dataSo ...

  9. left join 与left outer join的区别

    joinn 语句有三种:inner join, left outer join 和 right outer join都可以简写,分别为join,left join,right join.

  10. 【思维+贪心】codeforces Game of the Rows

    http://codeforces.com/contest/839/problem/B [题意] 给定n组人,告诉每组人的人数,这些人要在飞机上坐座位 飞机上座位的分布看图可以知道,12  3456 ...