C++学习——深入IO

深入IO

参考C++ IOStream

一、IOStream 概述

1.1 概述

IOStream 采用流式 I/O 而非记录 I/O ,但可以在此基础上引入结构信息

1.2 处理两个主要问题

  1. 表示形式的变化:使用格式化 / 解析在数据的内部表示与字符序列间转换(例如:二进制表示解析成字符)
  2. 与外部设备的通信:针对不同的外部设备(终端、文件、内存)引入不同的处理逻辑
    这里的外部设备是只IOStream外的广义设备。

1.3 所涉及到的操作(输出流)

  • 格式化 / 解析
  • 缓存
  • 编码转换
  • 传输

1.4 采用模板来封装字符特性,采用继承来封装设备特性

  • 常用的类型实际上是类模板实例化的结果

二、输入与输出

2.1 分类

  • 格式化
  • 非格式化

2.2 非格式化I/O

不涉及数据表示形式的变化

  • 常用输入函数:get / read / getline / gcout
  • 常用输入函数:put / write
    提升性能,对人不友好。

2.3 格式化I/O

使用移位操作符来进行的输入 (>>) 与输出 (<<)

  • C++ 通过操作符重载以支持内建数据类型的格式化 I/O
  • 可以通过重载操作符以支持自 定义类型的格式化 I/O
    对人 友好,可能牺牲一些性能。

2.4 格式控制

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z2nlZ1OX-1639836672530)(d96a81291d7a0dbbdf596bdb414400e9.png)]

2.5 操纵符

  • 简化格式化参数的设置
  • 触发实际的插入与提取操作
#include<iostream>
#include<iomanip>
int main()
{
	int x(22);
	std::cout <<std::showpos<< std::setw(10)<<std::setfill('.')
        << x << std::endl;	
	return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7Q9H4iCb-1639836672533)(98fb403f49c168ac5baa41ffe2ad921b.png)]

提取会放松对格式的限制

比如接受int 即使输入+10 空格10,接受的是10。

提取 C 风格字符串时要小心内存越界
#include<iostream>
#include<string>
int main()
{
	std::string z;
	std::cin >> z;
	std::cout << z << std::endl;

	char x[5];
	std::cin >> x;// 输入太长会越界。
    std::cin >> std::setw(4)>>x;// 这样可以限制。
	std::cout << x << std::endl;
	return 0;
}

三、文件操作

3.1 文件操作

  • basic_ifstream / basic_ofstream / basic_fstream
  • 文件流可以处于打开 / 关闭两种状态,处于打开状态时无法再次打开,只有打开时才能 I/O
#include<iostream>
#include<fstream>
using namespace std;
int main()
{
	std::ofstream outFile("my_file");
   // ...or
    std::ofstream outFile;
    outFile.open("my_file");
    outFile << "hello "
    outFile.close();
        
	cout << outFile.is_open() << endl;
	return 0;
}

3.2 文件流的打开方式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2sd0rfCk-1639836672534)(6feea5c5a101d6a8a7b0ac91c84fc21e.png)]
只输入文件名其实是缺省初始化

标记

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zy7ZAj4r-1639836672534)(514c67803e2d386fcdd1cc43ff40d8d2.png)]

  • std::ios_base::ate
    可以移动文件指针位置
  • std::ios_base::app
    只能在末尾
  • std::ios_base::trunc
    截断,删除之前的内容
  • 这些内容标记可以“ | ”运算
  • ::binary 能禁止系统特定的转换:: 比如"\n"不转换为回车

  • 避免意义不明确的流使用方式(如 ifstream + out )

3.3 合法的打开方式组合(引自 C++ IOStream 一书)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xbk3Ha19-1639836672535)(1a4f05d49664b1334bf10ff214813a4e.png)]

四、内存操作

4.1 内存流

  • 内存流: basic_istringstream / basic_ostringstream / basic_stringstream
#include<iostream>
#include<sstream>
#include<string>
using namespace std;
int main()
{
	std::ostringstream obj1 ;
	obj1 << 1234;//格式化 整数转字符串
	string res = obj1.str();
	cout << res << endl;//输出字符串1234
    
    std::istringstream obj2(res) ;
    int x;
    obj2 >> x;
    cout << x << endl;//输出int 1234
	return 0;
}

4.2 也受打开模式: in / out / ate / app 的影响

Note: 使用 str() 方法获取底层所对应的字符串
Note: 小心避免使用 str().c_str() 的形式获取 C 风格字符串
#include<iostream>
#include<sstream>
#include<string>
using namespace std;
int main()
{
	std::ostringstream obj1("1231231");
	auto c_res = obj1.str().c_str();
    //这是错误的 ,obj1.str()返回右值,用auto接受会变成指针,后续无法访问销毁的内存。
	cout << c_res << endl;

}
Note: 基于字符串流的字符串拼接优化操作

通过string字符串 str += “…” 方法会不断开辟内存拷贝释放,浪费资源
使用内存流 obj << “…” 会提升性能

五、流

5.1 流的状态

std::ios_base::iostate 位掩码类型
例如:

goodbit – 0000,0000 #
badbit – 0000,0001  # 不可恢复的流错误
faibit – 0000,0010  # 输入输出操作失败(格式化或提取错误)
eofbit– 0000,0100   # 关联的输入序列已经抵达末尾

检测流的状态

  • good( ) / fail() / bad() / eof() 方法
  • static_cast<\bool>(std::cin) 参考cppreference
#include<iostream>
using namespace std;
int main()
{
	int x;
    cin >> x;
	cout << cin.good();
    ...
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tJev7ViG-1639836672535)(b7397d59378785343151352f8758bf70.png)]

区分 fail 与 eof
– 可能会被同时设置,但二者含意不同
– 转换为 bool 值时不会考虑 eof
复位流状态
  • clear :设置流的状态为具体的值(缺省为 goodbit )
  • setstate :将某个状态附加到现有的流状态上
捕获流异常:exceptions方法

5.2 流的定位

5.2.1 获取流位置

– tellg() / tellp() 可以用于获取输入 / 输出流位置 (pos_type 类型 )
– 两个方法可能会失败,此时返回 pos_type(-1)

#include<iostream>
#include<sstream>
#include<string>
using namespace std;
int main()
{
	std::ostringstream s;

	cout << s.tellp() << '\n';
	s << "h";
	cout << s.tellp() << '\n';
	s << "ello, world ";
	cout << s.tellp() << '\n';
	s << 3.14 <<"\n";
	cout << s.tellp() << '\n'<< s.str();
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pILy9UiE-1639836672536)(582a4f410f9e839ba342aad15a96bea0.png)]
tellp()/ tellg()返回的是下一个可以写入/读取的位置

5.2.2 设置流位置
  1. seekg() / seekp() 用于设置输入 / 输出流的位置
  2. 这两个方法分别有两个重载版本:
    • 设置绝对位置:传入 pos_type 进行设置
    • 设置相对位置:通过偏移量(字符个数 ios_base::beg ) + 流位置符号的方式设置
      • ios_base::beg
      • ios_base::cur
      • ios_base::end
        ::注意标准io流 >> << 遇到空格回车等分隔符会停止::

5.3 流的同步

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

flush() 用于输出流同步,刷新缓冲区
– sync() 用于输入流同步,其实现逻辑是编译器所定义的
– 输出流可以通过设置 unitbuf 来保证每次输出后自动同步
cout<<std::unitbuf 关掉缓存区直接刷新。

5.3.2 基于绑定 (tie) 的同步

– 流可以绑定到一个输出流上,这样在每次输入 / 输出前可以刷新输出流的缓冲区
– 比如: cin 绑定到了 cout 上

5.3.3 与 C 语言标准 IO 库的同步

– 缺省情况下, C++ 的输入输出操作会与 C 的输入输出函数同步
– 可以通过 sync_with_stdio 关闭该同步

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值