• C++的IO流


    一、C语言的输入与输出

    scanfprintf是C语言中最为常用的输入输出。
    scanf(): 从标准输入设备(键盘)读取数据,并将值存放在变量中。
    printf(): 将指定的文字/字符串输出到标准输出设备(屏幕)。
    注意宽度输出和精度输出控制。
    C语言借助了相应的缓冲区来进行输入与输出。
    在这里插入图片描述
    对于输入输出缓冲区的理解:

    1.可以屏蔽掉低级I/O的实现,低级I/O的实现依赖操作系统本身内核的实现,所以如果能够屏蔽这部分的差异,可以很容易写出可移植的程序。
    2.可以使用这部分的内容实现“行”读取的行为,对于计算机而言是没有“行”这个概念,有了这部分,就可以定义“行”的概念,然后解析缓冲区的内容,返回一个“行”。

    二、流是什么

    在这里插入图片描述
    可以类比河流中流水一样,“流”即是流动的意思,是物质从一处向另一处流动的过程,是对一种有序连续且具有方向性的数据(其单位可以是bit,byte,packet)的抽象描述。 C++流是指信息从外部输入设备(如键盘)向计算机内部(如内存)输入和从内存向外部输出设备(显示器)输出的过程。这种输入输出的过程被形象的比喻为“流”。
    它的特性是:有序连续、具有方向性
    为了实现这种流动,C++定义了I/O标准类库,这些每个类都称为流/流类,用以完成某方面的功能

    三、C++IO流

    C++系统实现了一个庞大的类库,其中ios为基类,其他类都是直接或间接派生自ios类
    在这里插入图片描述

    3.1 C++标准IO流

    C++标准库提供了4个全局流对象cincoutcerrclog

    1. 使用cout进行标准输出,即数据从内存流向控制台(显示器)。
    2. 使用cin进行标准输入即数据通过键盘输入到程序中,
    3. 同时C++标准库还提供了cerr用来进行标准错误的输出,
    4. 使用clog进行日志的输出,

    从上图可以看出,cout、cerr、clog是ostream类的三个不同的对象,因此这三个对象现在基本没有区别,只是应用场景不同,在使用时候必须要包含文件并引入std标准命名空间

    注意

    1. cin为缓冲流。键盘输入的数据保存在缓冲区中,当要提取时,是从缓冲区中拿。如果一次输入过多,会留在那儿慢慢用,如果输入错了,必须在回车之前修改,如果回车键按下就无法挽回了。只有把输入缓冲区中的数据取完后,才要求输入新的数据。
    2. 输入数据类型必须与要提取的数据类型一致,否则出错。出错只是在流的状态字state中对应位置(置1),程序继续。
    3. 空格回车都可以作为数据之间的分格符,所以多个数据可以在一行输入,也可以分行输入。但如果是字符型和字符串,则空格(ASCII码为32)无法用cin输入,字符串中也不能有空格。回车符也无法读入。使用getline()输入。
    4. cin和cout可以直接输入和输出内置类型数据,原因:标准库已经将所有内置类型的输入和输出全部重载了。
    5. 对于自定义类型,如果要支持cin和cout标准输入输出,需要重载<<和>>
    6. 在线OJ常用:
      常常要求多组测试用例:
    //C语言中
    while(scanf("%d\n",&a)!=EOF)
    {
    	//数据处理
    	//ctrl+z退出
    }
    //C++中
    while(cin>>str)
    {
    	//数据处理
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    对于C++中的cin>>str,调用operator>>重载,转换为operator>>(cin,str),输入接收是用的对象作为while循环的判断条件,这显然是不合常理的,但是这里却是一个特殊的函数重载operator.bool( )
    举个例子:

    istream& operator>>(istream& in, Date& d)
    {
    	in >> d._year >> d._month >> d._day;
    	return in;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这里返回in,其实就是返回cin(这是一个对象)
    cin中又提供了对于类型运算符的重载operator bool,它会返回一个是否设置了错误标志(failbit或badbit)。

    while(对象)
    {} 
    转换成
    while(对象.operator bool())
    {}
    
    • 1
    • 2
    • 3
    • 4
    • 5

    如下例子:

    
    class B
    {
    public:
    	operator bool()
    	{
    		return _a != 0;
    	}
    	int _a;
    };
    int main()
    {
    	B b;
    	/*while (b)*/  // 等价于
    	while (b.operator bool())
    	{
    		cin >> b._a;
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    3.2 C++中文件读写操作

    要求:往配置文件中写入和读取信息

    struct ServerInfo
    {
    	char _ip[32];
    	int _port;
    };
    
    class ConfigManager
    {
    public:
    	ConfigManager(const char* filename)
    		:_filename(filename)
    	{}
    	void WriteBin(const ServerInfo & info)
    	{
    		// out到文件中
    		ofstream ofs(_filename.c_str(),ios_base::out|ios_base::binary);
    		ofs.write((const char*)&info,sizeof(ServerInfo));
    	}
    	void ReadBin(const ServerInfo& info)
    	{
    		ifstream ifs(_filename.c_str(), ios_base::in | ios_base::binary);
    		ifs.read(( char*)&info, sizeof(ServerInfo));
    	}
    
    	void WriteText(const ServerInfo& info)
    	{
    		ofstream ofs(_filename.c_str());
    		ofs << info._ip <<" "<< info._port ;
    
    	}void ReadText(ServerInfo& info)
    	{
    		ifstream ifs(_filename.c_str());
    		ifs >> info._ip >> info._port;
    	}
    private:
    	string  _filename;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    二进制读写

    // 写入
    void TestBinWite()
    {
    	ServerInfo info = { "126.0.0.1",90 };
    	ConfigManager cm("config.bin");
    	cm.WriteBin(info);
    }
    // 读取
    void TestBinRead()
    {
    	ServerInfo info ;
    	ConfigManager cm("config.bin");
    	cm.ReadBin(info);
    	cout << info._ip <<":"<< info._port << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    结果展示:
    在这里插入图片描述

    文本读写

    // 文本写入
    void TestTextWrite()
    {
    	ServerInfo info = { "126.0.0.1",90 };
    	ConfigManager cm("config.txt");
    	cm.WriteText(info);
    }
    // 文本读取
    void TestTextRead()
    {
    	ServerInfo info;
    	ConfigManager cm("config.txt");
    	cm.ReadText(info);
    	cout << info._ip << ":" << info._port << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    结果展示:
    在这里插入图片描述

    四、stringstream的简单介绍

    主要用途:将一些数据转换成一个字符串,或者将字符串转为数字

    struct Personinfo {
    	string _name;
    	int _age;
    };
    void Teststringstream()
    {
    	// 序列化
    	Personinfo p = {"张三",18};
    	ostringstream oss;
    	oss << p._name <<" "<< p._age;
    	string str = oss.str();
    	cout << str<<endl;
    	// 反序列化
    	istringstream iss(str);
    	string name;
    	int age;
    	iss >> name>>age;
    	cout << name << " " << age << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    要使用stringstream,必须要包含头文件<sstream>。在该头文件下,有三个类:

    1. ostringstream 输出操作
    2. istringstream 输入操作
    3. stringstream 输入操作+输出操作
  • 相关阅读:
    【字节码⻆度看synchronize】三种应用方式、Monitor类、monitorenter、monitorexit_JUC15
    互联网应用开发实践:MySQL数据库部署与操作(Docker、SpringBoot)
    create® 3入门教程-传感器检测
    规则引擎调研及初步使用
    RNN框架
    Promise花落谁家知多少
    Github每日精选(第35期):移动设备数据库Realm
    Maven学习笔记
    NLP工具再汇总
    通过SpringBoot+Vue+ElementUI+EasyExcel实现文件的导入导出
  • 原文地址:https://blog.csdn.net/weixin_57675461/article/details/124181425