【深蓝学院C++】第7章 深入IO 笔记

第7章 深入IO

1.IOStream 概述

(1)IOStream 采用流式 I/O

(2)处理的主要问题:

    表示形式的变化:使用格式化 / 解析在数据的内部表示与字符序列间转换

    与外部设备的通信:针对不同的外部设备(终端、文件、内存)引入不同的处理逻辑

(3)所涉及的操作

    格式化/解析

    缓存

    编码转换

    传输

2.输入和输出

(1)非格式化I/O:不涉及数据表示形式的变化

常用输入函数: get / read / getline / gcount

常用输入函数: put / write
int x;
std::cin.read(reinterpret_cast<char *>(&x), sizeof(x));    //非格式化输入
std::cout << x << std::endl;

(2)格式化I/O:使用移位操作符来进行的输入 (>>) 与输出 (<<)

C++ 通过操作符重载以支持内建数据类型的格式化 I/O

可以通过重载操作符以支持自定义类型的格式化 I/O

(3)格式控制

可接收位掩码类型( showpos )、字符类型( fill )与取值相对随意( width )的格式化参数
int main()
{
    char x = '0';
    std::cout.setf(std::ios_base::showpos);
    std::cout << x << std::endl;
    int y = static_cast<int>(x);
    std::cout << y <<std::endl;
}
int main()
{
    char x = '0';
    std::cout.setf(std::ios_base::showpos);
    std::cout.width(10);
    std::cout << x << std::endl;
    int y = static_cast<int>(x);
    std::cout << y <<std::endl;
}
int main()
{
    char x = '0';
    std::cout.setf(std::ios_base::showpos);
    std::cout.width(10);
    std::cout.fill('.');
    std::cout << x << std::endl;
    int y = static_cast<int>(x);
    std::cout << y <<std::endl;
}
注意 width 方法的特殊性:触发后被重置

(4)操纵符

#include <iomanip>
int main()
{
    char x = '0';
    int y = static_cast<int>(x);

    std::cout << std::showpos << std::setw(10) << std::setfill('.') << x << '\n' 
              << std::setw(10) << y << std::endl;
    /*
    std::cout.setf(std::ios_base::showpos);
    std::cout.width(10);
    std::cout.fill('.');
    std::cout << x << std::endl;
    std::cout << y <<std::endl;
    */
}

3.文件与内存操作

(1)文件操作

basic_ifstream / basic_ofstream / basic_fstream

文件流可以处于打开 / 关闭两种状态,处于打开状态时无法再次打开,只有打开时才能 I/O
#include <iostream>
#include <fstream>

int main()
{
    std::oftream outFile("my_file");
    outFile << "Hello\n";
}
#include <iostream>
#include <fstream>
#include <string>

int main()
{
    std::oftream inFile("my_file");
    std::string x;
    inFile >> x;
    std::cout << x << '\n '
}

(2)文件流的打开模式

每种文件流都有缺省的打开方式

注意 ate 与 app 的异同

binary 能禁止系统特定的转换

避免意义不明确的流使用方式(如 ifstream + out )
标记名作用
in打开以供读取
out打开以供写入
ate表示起始位置位于文件末尾
app附加文件,即总是向文件尾写入
trunc截断文件,即删除文件中的内容
binary二进制模式
#include <iostream>
#include <fstream>

int main()
{
    std::oftream outFile("my_file",std::ios_base::out);
    outFile << "Hello\n";
}
#include <iostream>
#include <fstream>

int main()
{
    std::oftream outFile("my_file",std::ios_base::out | std::ios_base::trunc);
    outFile << "Hello\n";
}

(3)合法的打开方式组合

打开方式效果加结尾模式标记加二进制模式标记
in只读方式打开文本文件初始文件位置位于文件末尾禁止系统转换
out|trunc out如果文件存在,将长度阶段为0;否则建立文件供写入初始文件位置位于文件末尾禁止系统转换
out|app附加;打开或建立文本文件,仅供文件末尾写入初始文件位置位于文件末尾禁止系统转换
in|out打开文本文件供更新使用(支持读写)初始文件位置位于文件末尾禁止系统转换
in|out|trunc如果文件存在,将长度截断为0;否则建立文件供更新使用初始文件位置位于文件末尾禁止系统转换

(4)内存流

basic_istringstream / basic_ostringstream / basic_stringstream
#include <iostream>
#include <sstream>

int main()
{
    std::ostringstream obj1;
    obj1 << 1234;
    std::string res = obj1.str();
    std::cout << res << std::endl;    //整数转换成了字符串
}
#include <iostream>
#include <sstream>
#include <iomanip>

int main()
{
    std::ostringstream obj1;
    obj1 << 1234;
    std::string res = obj1.str();

    std::istringstream obj2(res);
    int x;
    obj2 >> x;
    std::cout << x << std::endl;
}
也会受打开模式: in / out / ate / app 的影响
#include <iostream>
#include <sstream>

int main()
{
    std::ostringstream buf("test", std::ios_base::ate);
    buf << 1;
    std::cout << buf.str() << std::endl; 
}
#include <iostream>
#include <sstream>

int main()
{
    std::ostringstream buf("test");
    buf << 1;
    std::cout << buf.str() << std::endl; 
}
使用 str() 方法获取底层所对应的字符串,小心避免使用 str().c_str() 的形式获取 C 风格字符串

基于字符串流的字符串拼接优化操作
#include <iostream>
#include <sstream>

int main()
{
    std::string x;
    x += "Hello";
    x += " world";
    x += " hello";
    x += " world"; 
    std::cout << x << std::endl;

    std::ostringstream obj;
    obj << "Hello";
    obj << " world";
    obj << " hello";
    obj << " world";
    std::cout << obj.str() << std::endl;    //性能较好
}

4.流的状态

(1)iostate
failbit / badbit / eofbit / goodbit

goodbit 无错误

badbit 不可恢复的流错误

failbit 输入/输出操作失败(格式化或提取错误)

eofbit 关联的输出序列已抵达文件尾

(2)检测流的状态

good( ) / fail() / bad() / eof() 方法

转换为 bool 值
int x;
std::cin >> x;
std::cout << std::cin.good()
          << std::cin.fail()
          << std::cin.bad()
          << std::cin.eof()
          << static_cast<bool>(std::cin) << std::endl;

(3)注意区分fail与eof

可能会被同时设置,但二者含意不同

转换为 bool 值时不会考虑 eof

(4)复位流状态

clear :设置流的状态为具体的值(缺省为 goodbit )

setstate :将某个状态附加到现有的流状态上

5.流的定位

(1)获取流位置

tellg() / tellp() 可以用于获取输入 / 输出流位置 (pos_type 类型 )

两个方法可能会失败,此时返回 pos_type(-1)
#include <iostream>
#include <sstream>
int main()
{
    std::ostringstream s;
    std::cout << s.tellp() << '\n';
    s << 'h';
    std::cout << s.tellp() << '\n';
    s << "ello, world ";
    std::cout << s.tellp() << '\n';
    s << 3.14 << '\n';
    std::cout << s.tellp() << '\n' << s.str();
}

运行结果

0
1
13
18
hello, world 3.14
#include <iostream>
#include <string>
#include <sstream>

int main()
{
    std::string str = "Hello, world";
    std::istringstream in(str);
    std::string word;
    in >> word;
    std::cout << "After reading the word \"" << word
              << "\" tellg() returns " << in.tellg() << '\n';
}

运行结果

After reading the word "Hello," tellg() returns 6

(2)设置流位置

seekg() / seekp() 用于设置输入 / 输出流的位置
#include <iostream>
#include <string>
#include <sstream>

int main()
{
    std::string str = "Hello, world";
    std::istringstream in(str);
    std::string word1, word2;

    in >> word1;
    in.seekg(0); // 回溯
    in >> word2;

    std::cout << "word1 = " << word1 << '\n'
              << "word2 = " << word2 << '\n';
}

运行结果

word1 = Hello,
word2 = Hello,
#include <sstream>
#include <iostream>

int main()
{
    std::ostringstream os("hello, world");
    os.seekp(7);
    os << 'W';
    os.seekp(0, std::ios_base::end);
    os << '!';
    os.seekp(0);
    os << 'H';
    std::cout << os.str() << '\n';
}

运行结果

Hello, World!

6.流的同步

(1)基于 flush() / sync() / unitbuf 的同步

flush() 用于输出流同步,刷新缓冲区
#include <iostream>
#include <fstream>
#include <string>

int main()
{
    std::cout << "What's your name?\n" << std::flush;
    //\n + 刷新, c++提供了一个新的操纵符
    //即 std::endl
    std::string name;
    std::cin >> name;
}
sync() 用于输入流同步,其实现逻辑是编译器所定义的

输出流可以通过设置 unitbuf 来保证每次输出后自动同步

(2)基于绑定 (tie) 的同步

流可以绑定到一个输出流上,这样在每次输入 / 输出前可以刷新输出流的缓冲区

比如: cin 绑定到了 cout 上

(3)与 C 语言标准 IO 库的同步

缺省情况下, C++ 的输入输出操作会与 C 的输入输出函数同步

可以通过 sync_with_stdio 关闭该同步
#include <iostream>
#include <cstdio>

int main()
{
    std::ios::sync_with_stdio(false);
    std::cout << "a\n";
    std::printf("b\n");
    std::cout << "c\n";
}

可能的输出:

可以确定的是a在c之前

b
a
c
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值