C++输入输出与IO流

C++ 输入输出与I/O流

文章目录

  • C++ 输入输出与I/O流
    • IO类型与基础特性
      • 概念与特性
      • IO状态
      • 输出缓冲区
    • 文件输入输出
      • 文件模式
    • string流
    • IO处理中常用的函数及操作符
    • 综合练习与demo
      • 一、 创建文件并写入
      • 二、控制台输入数据并拆分存储
      • 三、读写电话簿

IO类型与基础特性

C++11标准提供了几种IO处理操作。其中最为熟悉的就是控制台IO:iostream,除此之外,还提供了文件操作IO:fstream以及string处理IO:stringstream,这两种IO操作都继承自iostream,因此在iostream上可以执行的操作,在另外两种IO类型中亦可执行。(i继承i,o继承o)

IO库类型及头文件

头文件类型作用
iostreamistream, wistream从流读取数据
ostream, wostream向流写入数据
iostream, wiostream读写流
fstreamifstream, wifstream从文件中读取数据
ofstream, wofstream向文件写入数据
fstream, wfstream读写文件
sstreamistringstream, wistringstream从string中读取数据
ostringstream, wostringstream向string中写入数据
stringstream, wstringstream读写string

注:w开头的类型用于操纵wchar_t类型的数据。

  • cin:一个istream对象,从标准输入中读取数据
  • cout: 一个ostream对象,向标准输出写入数据
  • cerr:一个ostream对象,通常用于输出程序错误信息,写入到标准错误
  • >>:用来从一个istream对象读取输入数据
  • <<: 用来向一个ostream对象写入输出数据
  • eof(): 用来判断流是否到达末尾

概念与特性

  • IO对象不能被拷贝或赋值
  • 如果程序崩溃,输出缓冲区是不会被刷新的。
  • 当一个输入流被关联到一个输出流时,任何试图从输入流读取数据的操作都会先刷新关联的输出流

IO状态

strm::iostate是C++中表示流的状态的一种类型,是一个枚举类型。(这里的strm是一种IO类型,如ostreamfstream等)

流状态类型说明
strm::badbit**表示流发生了无法恢复的错误,通常是系统级错误。**如果其对应置位被clear()清除,也只是将流状态恢复为有效,不会解决问题。
strm::falibit表示流操作失败,这种错误通常是可恢复的
strm::eofbit表示流到达了文件结束
strm::goodbit表示流处于正常状态,所有的标志位都是0

标准库提供了一组函数用来查询这些标志位的状态。其中good()fail()是确定流总体状态的方法,当我们将流当做条件使用,如while(cin >> word)时,其代码就等价于while(!cin.fail())

状态查询方法说明
s.eof()若流s的eofbit置位,则返回true
s.fail()若流s的falibitbadbit置位,则返回true
s.bad()若流s的badbit置位,则返回true
s.good()若流s处于有效状态,则返回true
s.clear()将流s中所有条件状态复位,将流的状态设置为有效。void类型
s.clear(flags)复原指定的flags标志位。void类型
s.setstate(flags)复原给定的flags标志位。void类型
s.rdstate()返回的是当前流的状态,以 iostate 枚举值表示。

输出缓冲区

每个输入流都管理一个缓冲区,用来保存程序读写的数据。

当程序正常结束、缓冲区满、手动指定缓冲(如操作符endl,cerr等)缓冲区都会被刷新。

操作符说明
std::endl换行并刷新缓冲区
std::flush刷新缓冲区,且不附加额外字符
std::ends输出空字符,并刷新缓冲区

unitbuf与nounitbuf

cout << unitbuf; 		// 所有输出操作后都会立刻刷新缓冲区
// 任何输出都立刻刷新,无缓冲
...
cout << nounitbuf;      // 恢复常规模式

文件输入输出

fstream特有的操作

操作说明
fstream fstrm;创建一个未绑定的文件流
fstream fstrm(s);创建一个文件流,并打开名为s的文件(s可为string,亦可为C风格字符串之指针)。此构造函数是explicit的
fstream fstrm(s, mode)与上者类似,按指定mode打开指定s文件
fstrm.open(s)打开名为s的文件,并将文件与fstrm绑定
fstrm.close()关闭与fstrm绑定的文件。void类型
fstrm.is_open()返回一个bool值,说明关联文件是否成功打开且尚未关闭
  • 当一个fstream对象被销毁时,close会自动被调用

文件模式

文件模式,用于指出文件流如何使用文件

文件模式说明
in以读的方式打开
out以写的方式打开
app每次写操作之前均定位到文件末尾
ate打开文件后立即定位到文件末尾
trunc截断文件
binary以二进制方式进行IO
  • ifstream默认in模式,ofstream默认out模式,fstream默认inout模式
  • out只支持ofs和fs流; in只支持ifs和fs流
  • out被设定时,才可以设定trunc
  • trunc没被设定时,才可以设定app模式
  • app模式下,没有显式指定out,文件依然以输出方式被打开
  • atebinary模式可用于任何类型的文件流对象

注意1:以out模式打开文件会丢弃已有数据

  • 使用ofstream打开一个文件,会将文件原有的数据丢弃。可以同时采用显式指定appin的方式打开,避免造成数据丢失。

注意2:每次调用open是都会确认文件模式

  • 我们使用同一个ofstream流打开文件,在第一个文件指定了什么模式打开,并不会在第二个文件中依然存在,只会选择默认方式
  • 所以我们利用与out相关的文件流打开文件时,一定要注意最好显式指定文件模式

我们使用文件流时通常包含以下步骤

  • 创建一个文件流
    • 默认文件流
    • 指定绑定文件(打开or不打开)
  • 打开文件
    • 显式指定打开模式
  • 关闭文件
void fstreamTest(){
    string filename = "F:xxxxxx\\test.txt";
    // 创建一个文件流对象
    std::fstream fstrm(filename);
    // fstrm.open(filename);  也可以创建一个默认的fstream实例,用这种方式打开
    
    string line;
    // 是否成功打开与其关联的文件
    if(fstrm.is_open()){
        while(std::getline(fstrm, line)){
            std::cout<< line << std::endl;
        }
    }else{
        std::cerr<<"Flie is not open!"<<std::endl;
    }
    // 最后用完关闭
    fstrm.close();
}

string流

stringstream特有操作

操作说明
sstream strm一个未绑定的string流对象
sstream strm(s)创建一个string流对象,并保存string s的拷贝(该构造函数explicit)
strm.str()返回strm保存的string的拷贝
strm.str(s)将s拷贝到strm中。void类型

IO处理中常用的函数及操作符

getline(cin, str)

  • getline函数会从输入流中读取字符,直到遇到换行符或者指定分隔符位置,会将读取到的字符存储在str中
template <class charT, class traits, class Allocator>
std::basic_istream<charT,traits>& getline (std::basic_istream<charT,traits>& is, std::basic_string<charT,traits,Allocator>& str, charT delim);
  • is 是输入流,例如 std::cin
  • str 是要存储读取到的一行数据的字符串。
  • delim 是可选参数,用于指定行结束的分隔符,默认为换行符 \n

std::boolalpha

  • 使控制台在输入bool类型数据时,输出字符型的truefalse,而非0和1
  • 关闭使用:std::noboolalpha
void boolalphaTest(){
    std::cout<<"Default bool type: "<<true<<" "<<false<<'\n'
            <<std::boolalpha
            <<"use boolalpha: "<< true<<" "<<false<<'\n'
            <<std::noboolalpha
            <<"close boolalpha: "<< true<<" "<<false<<'\n';
}

image-20240429223253041

综合练习与demo

一、 创建文件并写入

	std::ofstream outFile;			// 创建写入文件流
	outFile.open("emptable1.txt"); 	// 创建该txt文件
	if (!outFile)
	{
		std::cerr << "无法打开文件" << std::endl;
		return;
	}
	outFile << "on, ";				// 写入数据
	for (auto s : stepMap)
	{
		outFile << s.second << ", ";
	}
	outFile << endl;
	outFile.close();				// 关闭文件

二、控制台输入数据并拆分存储

/*1、输入一行数据并按空格拆分*/
string input;
vector<string> latex;
cout << "Please input: ";
// 将一行输入存储到input中
std::getline(std::cin, input);		
// 创建istring流,并将input拷贝过去
std::istringstream iss(input);				
string str;
// istring流将通过空格进行拆分,传递赋值给str
while (iss >> str)							
{
    latex.push_back(str);
}

/*2、输入多行数据并按行存储*/
 std::vector<std::string> lines;
std::string line;

std::cout << "Enter multiple lines of text (enter an empty line to finish):" << std::endl;

// 使用 getline 在循环中读取每一行输入
while (true) {
    std::getline(std::cin, line);
    if (line.empty()) {
        // 当输入为空行时,结束输入
        break;
    }
    lines.push_back(line);
}

三、读写电话簿

给定一个电话簿文件,里面格式大致为name number1 number2

读取该文件,并且存储人物及电话号码信息,存储时判断号码是否符合规定

将正确格式化后的字符,输出到结果文件中(结果文件包含title,不能覆盖)

image-20240429230735986

原始读取文件

image-20240429230808682

原始存储文件
#include <fstream>
#include <iostream>
#include <vector>
#include <sstream>
using namespace std;

struct PersonInfo
{
    /* data */
    string name;
    vector<string> phones;
};

// 检查电话号码是否合法
bool checkNumber(string s)
{
    if (s.size() != 11 && (s.size() < 4 || s.substr(0, 4) != "0831"))
    {
        return false;
    }
    else
    {
        for (auto &c : s)
        {
            if (!isdigit(c) && c != '-')
            {
                return false;
            }
        }
    }
    return true;
}

// 阅读最初的电话簿并存储
vector<PersonInfo> getOriginNumbers(string s)
{
    ifstream ifstm;
    // 文件输入流以默认模式打开文件
    ifstm.open(s);
    vector<PersonInfo> people;
    if (ifstm.is_open())
    {
        string line, number;
        // line以行存储文件中的内容
        while (getline(ifstm, line))
        {
            PersonInfo info;
            // 使用istringstream流时,record会根据空白符号对string进行拆分
            istringstream record(line);
            // 录入名字
            record >> info.name;
            // 录入多个号码
            while (record >> number)
            {
                info.phones.push_back(number);
            }
            people.push_back(info);
        }
    }
    else
    {
        cerr << "Open file is faild! " << endl;
    }
    ifstm.close();
    return people;
}

// 将正确的电话存储到电话簿中
void saveRightNumbers(vector<PersonInfo> &people, string s)
{
    ofstream ofs;
    // 以追加形式打开,避免覆盖文件中原有的内容
    ofs.open(s, ofstream::app);
    
    if (ofs.is_open())
    {
        for (const PersonInfo &p : people)
        {
            ofs<<'\n';      // 先换行
            // 记录哪些电话号码有误
            ostringstream badNums;
            ofs << p.name<<"    ";
            for (const auto &number : p.phones)
            {
                // 如果电话号码错误,存储到该string输出流中
                if (!checkNumber(number))
                {
                    // 存储多个错误号码
                    badNums << " " << number;
                }else{
                    ofs<<number << "    ";
                }
            }
            if (!badNums.str().empty())
            {
                // 输出谁的电话号码有问题
                cerr << "[input error]  name: " << p.name
                     << ",  invalid number(s): " << badNums.str() << endl;
            }
        }
    }
    else
    {
        cerr << "Open savefile is faild! " << endl;
    }
    ofs.close();
}

int main()
{
    string originfile = "F:\\xxxxxx\\numberDict.txt";
    string savefile = "F:\\xxxxxxx\\save.txt";
    vector<PersonInfo> people = getOriginNumbers(originfile);
    saveRightNumbers(people, savefile);
    return 0;
}

image-20240429231037247

控制台输出

image-20240429231057014

运行后的save文件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/693952.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

string经典题目(C++)

文章目录 前言一、最长回文子串1.题目解析2.算法原理3.代码编写 二、字符串相乘1.题目解析2.算法原理3.代码编写 总结 前言 一、最长回文子串 1.题目解析 给你一个字符串 s&#xff0c;找到 s 中最长的回文子串。 示例 1&#xff1a; 输入&#xff1a;s “babad” 输出&am…

Spring @Transactional 事务注解

一、spring 事务注解 1、实现层(方法上加) import org.springframework.transaction.annotation.Transactional;Transactional(rollbackFor Exception.class)public JsonResult getRtransactional() {// 手动标记事务回滚TransactionAspectSupport.currentTransactionStatus…

# 梯影传媒T6投影仪刷机方法及一些刷机工具链接

梯影传媒T6投影仪刷机方法及一些刷机工具链接 文章目录 梯影传媒T6投影仪刷机方法及一些刷机工具链接1、安装驱动程序2、备份设备rom【boot、system】3、还原我要刷进设备的rom【system】4、打开开发者模式以便于安装apk5、root设备6、更多好链接&#xff1a; 梯影传媒T6使用的…

【嵌入式】波特率9600,发送8个字节需要多少时间,如何计算?

问题&#xff1a; 波特率9600&#xff0c;发送 01 03 00 00 00 04 44 09 (8字节) 需要多少时间&#xff0c;如何计算&#xff1f; 在计算发送数据的时间时&#xff0c;首先要考虑波特率以及每个字符的数据格式。对于波特率9600和标准的UART数据格式&#xff08;1个起始位&…

预期值与实际值对比

编辑实际值和预期值变量 因为在单独的代码当中&#xff0c;我们先定义了变量str&#xff0c;所以在matcher时传入str参数&#xff0c;但当我们要把这串代码写在testrun当中&#xff0c;改下传入的参数&#xff0c;与excel表做连接 匹配的结果是excel表中的expect结果&#xf…

质量小议38 -- 60岁退休的由来

总是要有个标准&#xff0c;质量更是如些。 标准不是固定不变的&#xff0c;与时俱进。 关键词&#xff1a;当时的人均寿命&#xff1b;渐进式 60岁退休。 22大学毕业开始工作&#xff08;当然可能会更早&#xff09;&#xff0c;到60岁退休&#xff0c;要工作38年。 …

从零入手人工智能(2)——搭建开发环境

1.前言 作为一名单片机工程师&#xff0c;想要转型到人工智能开发领域的道路确实充满了挑战与未知。记得当我刚开始这段旅程时&#xff0c;心中充满了迷茫和困惑。面对全新的领域&#xff0c;我既不清楚如何入手&#xff0c;也不知道能用人工智能干什么。正是这些迷茫和困惑&a…

SpringBoot+Vue体育馆管理系统(前后端分离)

技术栈 JavaSpringBootMavenMySQLMyBatisVueShiroElement-UI 角色对应功能 学生管理员 功能截图

(四)React组件、useState

1. 组件 1.1 组件是什么 概念&#xff1a;一个组件就是用户界面的一部分&#xff0c;它可以有自己的逻辑和外观&#xff0c;组件之间可以相互嵌套&#xff0c;也可以复用多次。 组件化开发可以让开发者像搭积木一样构建一个完整的庞大应用 1.2 React组件 在React中&#xf…

java中集合List,Set,Queue,Map

Java SE中的集合框架是一组用于存储和操作对象的类和接口。它提供了丰富的数据结构&#xff0c;可以用于解决各种问题。Java SE中的集合框架包含以下主要类和接口&#xff1a; 一. Collection接口&#xff1a; 是集合框架的根接口&#xff0c;它定义了一些通用的集合操作方法…

kafka-生产者事务-数据传递语义事务介绍事务消息发送(SpringBoot整合Kafka)

文章目录 1、kafka数据传递语义2、kafka生产者事务3、事务消息发送3.1、application.yml配置3.2、创建生产者监听器3.3、创建生产者拦截器3.4、发送消息测试3.5、使用Java代码创建主题分区副本3.6、屏蔽 kafka debug 日志 logback.xml3.7、引入spring-kafka依赖3.8、控制台日志…

推荐云盘哪个好,各有各的优势

选择合适的云盘服务是确保数据安全、便捷分享和高效协作的关键。下面将从多个维度对目前主流的云盘服务进行详细的对比和分析&#xff1a; 速度性能 百度网盘青春版&#xff1a;根据测试&#xff0c;其上传和下载确实不限速&#xff0c;但主要定位是办公人群&#xff0c;适用于…

JavaScript基础(十二)

截取字符串 //对象名.toLowerCase();将字符串转为小写 var strLAOWANG; strstr.toLowerCase(); console.log(str); //对象名.toUpperCase();将字符串转为大写 var str1laowang str1str1.toUpperCase(); console.log(str1); 截取字符串 //方法1&#xff1a;对象名.substr(a,b); …

JS(JavaScript)的引用方式介绍与代码演示

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

android 抓取 logcat 日志的方法

1.找到这个路径 2.然后执行命令&#xff08;adb logcat -v time >.\\logcat.log&#xff09;&#xff0c;开始抓取日志 3.这个时候就可以去操作APP了&#xff0c;复现BUG了。 Ctrlc 结束日志抓取 adb logcat -c 清空旧日志

seerfar选品功能,OZON运营插件工具seerfar

在当今这个数字化、信息化的时代&#xff0c;电子商务的飞速发展使得越来越多的商家开始关注如何更高效地运营自己的在线店铺。其中&#xff0c;选品作为电商运营的重要一环&#xff0c;直接影响着店铺的流量、转化率和利润。在OZON这样的电商平台上&#xff0c;如何快速、准确…

7天搞定Python必背500单词

必备必记-你的Python就牛掰了 每天只背100个就足够了 老话说的好基础不扎实,地动山摇,在学习Python的时候前期基础很重要. 下面是大家常用遇到的Python基础单词,帮助你更好地掌握Python语言: 1.变量 在Python中用来存储数值,文本或其他信息的名称. 2. 函数 用于执行特定…

力扣2444.统计定界子数组的数目

力扣2444.统计定界子数组的数目 观察到不满足条件的数 可以作为天然的分割线 因此在枚举右端点的过程中 预处理minK&#xff0c;maxK和分割线上一次出现的下标 res min(min_i,max_i) - i0; 但是因为可能在到下个区段时 min_i和max_i尚未更新 导致结果为负数 所以要跟0再取一…

linux:如何硬盘分区扩容

文章目录 1. 前言2. 硬盘分区2.1 查看硬盘2.2 分区2.3 格式化 3. 硬盘分区扩容3.1 创建物理卷3.2 扩展到卷组&#xff08;volume group&#xff09;3.3 合并到待拓展分区3.4 使扩展生效 4 .参考 1. 前言 本文介绍如何将剩余的空间扩展到已有的硬盘分区中。 安装虚拟机的教程&…

VBA高级应用30例应用2实现在列表框内及列表框间实现数据拖动

《VBA高级应用30例》&#xff08;版权10178985&#xff09;&#xff0c;是我推出的第十套教程&#xff0c;教程是专门针对高级学员在学习VBA过程中提高路途上的案例展开&#xff0c;这套教程案例与理论结合&#xff0c;紧贴“实战”&#xff0c;并做“战术总结”&#xff0c;以…