C++的IO类库

在C语言中,用printf和scanf进行输入输出,往往不能保证所输入输出的数据是可靠的安全的。在C++的输入输出中,编译系统对数据类型进行严格的检查,凡是类型不正确的数据都不可能通过编译。因此C++的I/O操作是类型安全(type safe)的。 C++的I/O操作是可扩展的,不仅可以用来输入输出标准类型的数据,也可以用于用户自定义类型的数据。C++对标准类型的数据和对用户声明类型数据的输入输出,采用同样的方法处理。C++通过I/O类库来实现丰富的I/O功能。

1. IO类

类 fstream 和 stringstream 都是继承自类 iostream 的。输入类都继承自 istream,输出类都继承自 ostream。因此,可以在 istream 对象上执行的操作,也可在 istream 或 istringstream 对象上执行。继承自 ostream 的输出类也有类似情况。

istream(输入流)类型,提供输入操作。
ostream(输出流)类型,提供输出操作。
cin,一个 istream 对象,从标准输入读取数据。
cout,一个 ostream 对象,向标准输出写入数据。
cerr,一个 ostream 对象,通常用于输出程序错误信息,写入到标准错误。
clog,clog流对象也是标准错误流,它是console log的缩写。它的作用和cerr相同,都是在终端显示器上显示出错信息。区别:cerr是不经过缓冲区,直接向显示器上输出有关信息,而clog中的信息存放在缓冲区中,缓冲区满后或遇endl时向显示器输出。
>>运算符,用来从一个 istream 对象读取输入数据。
<<运算符, 用来向一个 ostream 对象中写入输出数据。

getline 函数,从一个给定的 istream 读取一行数据,存入一个给定的 string 对象中。

eof 函数,从输入流读取数据,如果到达文件末尾(遇文件结束符),eof函数值为非零值(真),否则为0(假)。
peak 函数,peek是“观察”的意思,peek函数的作用是观测下一个字符。其调用形式为: c=cin.peek( ), 函数的返回值是指针指向的当前字符,但它只是观测,指针仍停留在当前位置,并不后移。如果要访问的字符是文件结束符,则函数值是EOF(-1)。
putback 函数,其调用形式为 cin.putback(ch),其作用是将前面用get或getline函数从输入流中读取的字符ch返回到输入流,插入到当前指针位置,以供后面读取。
ignore 函数,其调用形式为 cin.ignore(n, 终止字符),函数作用是跳过输入流中n个字符,或在遇到指定的终止字符时提前结束(此时跳过包括终止字符在内的若干字符),也可以不带参数或只带一个参数,如:
cin.ignore() // n默认值为1,终止字符默认为EOF, 相当于ignore(1, EOF)

IO库条件状态

strm::iostate   strm 是一种IO类型,iostate 是一种机器相关的类型,提供了表达条件状态的完整功能

strm::badbit    用来指出流已崩溃
strm::failbit   用来指出一个IO操作失败了
strm::eofbit    用来指出流到达了文件结束
strm::goodbit   用来指出流未处于错误状态,此值保证为0

s.eof()         若流 s 的 eofbit 置位,则返回 true
s.fail()        若流 s 的 failbit 或 badbit 置位,则返回 true
s.bad()         若流 s 的 badbit 置位,则返回 true
s.good()        若流 s 处于有效状态,则返回 true
s.clear()       将流 s 中所有条件状态复位,将流的状态设置为有效,返回void

s.clear(flags)  根据给定的flag标志位,将流 s 中对应条件状态复位,flags 的类型为 strm::iostate。返回void

s.setstate(flags) 根据给定的flag标志位,将流 s 中对应条件状态置位,flags 的类型为 strm::iostate。返回void

s.rdstate()     返回流 s 的当前条件状态,返回值类型为 strm::iostate

endl操作符: 换行并刷新缓冲区,cout << endl;
flush操作符: 刷新缓冲区,不输出任何额外的字符,cout << flush;
ends操作符: 输出一个空字符并刷新缓冲区,cout << ends;
unitbuf操作符: cout << unitbuf; // 所有输出操作后都会立即刷新缓冲区,无缓冲。
nounitbuf操作符: cout << nounitbuf; // 重置流,恢复使用正常系统管理的缓冲区刷新机制

2. 文件输入输出

头文件 fstream 定义了三个类型来支持文件IO: ifstream 从一个给定文件读取数据, ofstream 向一个给定文件写入数据,以及 fstream 可以读写给定文件。

fstream 特有的操作

fstream fstrm;      创建一个未绑定的文件流, fstream 是头文件 fstream 中定义的一个类型

fstream fstrm(s);   创建一个 fstream, 并打开名为 s 的文件, s 可以是 string 类型,或者指向字符串的指针。这些构造函数都是 explicit 的,默认文件模式依赖于 fstream 的类型

fstream fstrm(s, mode); 与前一个构造函数类似,但按指定 mode 打开文件

fstrm.open(s);      打开名为 s 的文件, 并将文件与fstrm 绑定,s 可以是 string 类型,或者指向字符串的指针。这些构造函数都是 explicit 的,默认文件模式依赖于 fstream 的类型,返回 void

fstrm.close();      关闭与 fstrm 绑定的文件,返回 void

fstrm.is_open();    返回一个 bool 值,指出与 fstrm 关联的文件是否成功打开且尚未关闭

文件模式(mode)

in          以读方式打开
out         以写方式打开,隐含截断文件
app         每次写操作前均定位到文件末尾,隐含输出模式
ate         打开文件后立即定位到文件末尾
trunc       截断文件
binary      以二进制方式进行IO
// example8_8.cpp 追加写入文件示例
#include <iostream>
#include <fstream>
#include "Sales_data.h"

using namespace std;

int main(int argc, char *argv[])
{
    if (argc != 3) {
        cerr << "请给出输入、输出文件名" << endl;
        return -1;
    }

    ifstream in(argv[1]);
    if (!in) {
        cerr << "无法打开输入文件" << endl;
        return -1;
    }
    ofstream out(argv[2], ofstream::app);
    if (!out) {
        cerr << "无法打开输出文件" << endl;
        return -1;
    }

    Sales_data total;               // 保存当前求和结果的变量
    if (read(in, total)) {          // 读入下一笔交易
        Sales_data trans;           // 保存下一条交易数据的变量
        while (read(in, trans)) {   // 读入剩余的交易
            if (total.isbn() == trans.isbn()) {     // 检查isbn
                total.combine(trans);               // 更新变量total当前的值
            } else {
                print(out, total) << endl;          // 输出结果
                total = trans;                      // 处理下一本书
            }
        }
        print(out, total) << endl;                  // 输出最后一条交易
    } else {                                        // 没有输入任何信息
        cerr << "没有数据" << endl;                 // 通知用户
    }

    return 0;
}

这里写图片描述

3. string流

sstream 头文件定义了三个类型来支持内存IO,istringstream 从 string 读取数据,ostringstream向 string 写入数据,stringstream 既可从 string 读数据,也可向 string 写数据,就像 string 是一个IO流一样。

stringstream 特有的操作

sstream strm;   strm 是一个未绑定的 stringstream 对象。stream 是头文件 sstream 中定义的一个类型

sstream strm(s); strm 是一个 sstream 对象,保存 string s 的一个拷贝,此构造函数是 explicit 的

strm.str();     返回 strm 所保存的 string 的拷贝

strm.str(s);    将 string s 拷贝到 strm 中,返回 void
// example8_13.cpp 测试 stringstream
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

struct PersonInfo {
    string name;
    vector<string> phones;
};

string format(const string &s) {
    return s;
}

bool valid(const string &s) {
    return true;
}

int main(int argc, char *argv[])
{
    string line, word;          // 分别保存来自输入的一行和单词
    vector<PersonInfo> people;  // 分别保存来自输入的所有记录
    istringstream record;

    if (argc != 2) {
        cerr << "请给出文件名" << endl;
        return -1;
    }
    ifstream in(argv[1]);
    if (!in) {
        cerr << "无法打开输入文件" << endl;
        return -1;
    }

    while (getline(in, line)) {
        PersonInfo info;        // 创建一个保存此记录
        record.clear();         // 重复使用字符串流时,每次都要调用clear
        record.str(line);       // 将记录绑定到刚读入的行
        record >> info.name;    // 读取名字
        while (record >> word) {            // 读取电话号码
            info.phones.push_back(word);    // 保存它们
        } 
        people.push_back(info);             // 将此记录追加到people末尾
    }

    ostringstream os;
    for (const auto &entry : people) {              // 对people中每一项
        ostringstream formatted, badNums;           // 每个循环步创建的对象
        for (const auto &nums : entry.phones) {     // 对每个数
            if (!valid(nums)) {
                badNums << " " << nums;             // 将数的字符串形式存入badNums
            } else {
                // 将格式化的字符串“写入”formatted
                formatted << " " << format(nums);
            }
        }
        if (badNums.str().empty()) {            // 没有错误的数
            // 打印名字和格式化的数
            os << entry.name << " " << formatted.str() << endl;
        } else {
            // 打印名字和错误的数
            cerr << "input error: " << entry.name 
            << " invalid number(s) " << badNums.str() << endl;
        }
    }
    cout << os.str() << endl;

    return 0;
}

这里写图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章