C/C++语言基础--C++IO流、输入输出流、文件流、字符串流、重定向流等详解

本专栏目的

  • 更新C/C++的基础语法,包括C++的一些新特性

前言

  • 流思想,我认为在计算机中是一个很重要的思想,因为计算机、编程无非就是获取数据,然后对数据进行操作;
  • C++给主要给我们提供了3种流,输入输出流、文件流、字符串流,这篇就是小编的学习笔记,希望大家能够批评指正。

文章目录

    • IO流
    • 标准输入输出流
      • 类和流对象
      • 标准输入流
        • >>读取
        • cin.get()
        • cin.getine()
        • cin.ignore
      • 标准输出流
    • 文件流
      • 简介
      • 使用
        • 打开文件
        • 读取文件
          • 使用>>读取
          • 使用read()读取
          • 使用std::getline读取
        • 写入文件
          • 使用<<写入
          • 使用write写入
      • 打开模式
      • 文件位置指针
      • 文件操作的一些函数
    • 字符串流
      • 打开字符串流
      • 从string反格式化
    • 重定向流
      • 代码实重定向
        • C语言方式
        • C++方式

IO流

咱已经学过了 C 语言,所以都知道,C语言有有一整套完成数据读写(I/O)的解决方案:

  • 使用 scanf()、gets() 等函数从键盘读取数据,使用 printf()、puts() 等函数向屏幕上输出数据;
  • 使用 fscanf()、fgets() 等函数读取文件中的数据,使用 fprintf()、fputs() 等函数向文件中写入数据。
  • 使用sscanf() 读取格式化的字符串中的数据,使用sprintf()把格式化的数据写入到字符串

要知道,C 语言的这套 I/O 解决方案也适用于 C++ 程序,但 C++ 自己独立开发了一套全新的 I/O 解决方案,其中就包含大家一直使用的 cin 和 cout,但是要注意,cin、cout是类,printf、scanf是函数调用。

C++标准流,提供了一下三个方面的内容:

  1. 系统指定的标准设备的输入和输出。即从键盘输入数据,输出到显示器屏幕,简称标准I/O。
  2. 外存磁盘文件为对象进行输入和输出,简称文件I/O。
  3. 内存中指定的空间进行输入和输出,,简称串I/O。

流的概念:数据传输,输入、输出像水一样,故将这个过程定义为流。

标准输入输出流

类和流对象

重点关注前两个即可。

流类预定义流对象描述
istreamcin(常用)标准输入流
ostreamcout(常用)标准输出流
ostreamcerr标准错误流(不缓冲数据,直接显示)
ostreamclog标准日志流(缓冲数据)

标准库定义了 4 个 IO 对象。

  • 处理输入时使用命名为cin的 istream 类型对象,称为标准输入。

  • 处理输出时使用命名为cout的 ostream 类型对象,称为标准输出。

  • 标准库还定义了另外两个 ostream 对象,分别命名为 cerr 和 clog,cerr 对象又叫作标准错误,通常用来输出警告和错误信息给程序的使用者。

  • 而 clog 对象用于产生程序执行的一般信息。

标准输入流

cin本身是会略过所有空格、回车、tab的,然后开始读入,遇到空格、回车、tabl停止读入,光标会停留在这些字符之前,意思就是下一次读入也会从空格后开始读取。

>>读取

C++给我们提供了方便的输入方法,直接使用>>即可,但是遇到空格会被截断

cin.get()

读取一个字符,也可以连续读取

char c;
char buf[20],buf1[20];
//读取一个字符
c = cin.get();	//<==> cin.get(c);
//读取字符串
cin.get(buf, 20);
//读取字符串,遇到指定的字符终止读取
cin.get(buf1, 20, '#');
cout << c << " " << buf<<" "<< buf1;
cin.getine()

读取一行

char buf[20];
cin.getline(buf, 20);
cin.getline(buf, 20, '#');
cin.ignore

忽略

std::string str;
//忽略所有\n
while (cin.peek() == '\n')
{
	cin.ignore(1);
}	
std::getline(cin, str,'#');
// 输出
cout << str << endl;
/*
输入:
\n
\n
123#
输出:
123
*/

标准输出流

C++格式化输出3种使用方式:

  1. 通过流成员函数进行输入输出格式控制
// 设置输出内容宽度
cout.width(30);
// 设置填充内容
cout.fill('*');
// 设置对其方式
cout.setf(ios::left);
// 用科学计数法展示
cout.setf(ios::scientific);

// 八进制格式输出
cout << oct << 0xA << endl;
// 十进制格式输出
cout << dec << OxA << endl;
// 大写形势展示十六进制中字母
cout.self(ios::uppercase);
// 十六进制格式显示
cout << hex << OxA << endl;

// 取消科学计数法使用
cout.unself(ios::scientific);
// 设置浮点数显示前N位
cout.precision(3);
cout << 3.1415 << endl;  // 输出 3.142,最后一位四舍五入

// ………………………… 还有很多,现用现查即可。

这里有些设置会全局生效,所以有还需要关闭,时候很不方便。

  1. 通过#include 提供的控制符,进行输入输出格式控制,如下:
控制符作用
setbase(n)设置整数为n进制
setfill(n)设置字符填充
setprecision(n)设置浮点数有效位
setw()设置字段宽度
setiosflags(ios::fixed)设置浮点数固定小数位输出
setiosflags(ios::scientific)浮点数以科学计数法表示
setiosflags(ios::left)左对齐
setiosflags(ios::right)右对齐

当然还有很多,先用现查即可。

案例

cout << setw(30) << setfill('*') << setiosflags(ios::left) << 1.2222233 << endl;

// 输出: 1.22222***********************

而且这个具有临时性,不会影响后面输出。

  1. 运用C语言的API

可以用C语言的scanf进行格式化输出。

文件流

简介

文件:字节流,即如何从文件读取流和向文件写入流。

C++ 给操作文件提供了一个标准库 fstream,它定义了三个新的数据类型:

在这里插入图片描述
在这里插入图片描述

使用

其实任何语言文件操作都差不多,打开、关闭、读取与写入(字节、一行、二进制等)

打开文件
fstream file("maye.txt");

可以通过构造函数指定文件名,并打开;默认就是以可读可写的方式打开的,但是文件不存在会打开失败!

file.open("maye.txt", ios::in | ios::out | ios::trunc);

也可以使用open函数打开文件,使用open必须传递打开模式ios::in为可读,ios::out为可写,ios::trunc为文件不存在时创建,存在则清空所有内容(ios::trunc必须与ios::out搭配使用)。

if (!file)	//if (!file.is_open())	//两种判断方式都可以
{
	cout << "open error:" << strerror(file.rdstate());
}
else
{
	cout << "open successed";
}

file.close();

注意: 使用完毕之后并不需要手动关闭文件,但是如果想提前关闭可以使用close()函数。

读取文件

文件打开之后,就可以进行读写了,注意打开模式,ios::in为可读,ios::out为可写。

创建stu.txt文件,并写入以下内容,并测试读取!

123 wy 男
456 lt 男
789 wgs 男
110 lyp 男

如果乱码,则将文件存为ansi(win11中记事本)

使用>>读取
std::string buf;
while (!file.eof())  // 判断是否读到了文件最后
{
	file >> buf;		//读成功返回true
	cout << buf << " ";
	if (file.peek() == '\n')
	{
		cout << endl;
	}
}

注意,使用>>读取,遇到空格会截断,所以需要循环的去读取,而且还需要自己判断是不是\n。

使用read()读取
char buf[200] ={0};
file.read(buf, 200);
cout << buf;

注意:我们并不知道文件有多大,所以并不能很好的指定读取的大小,从而一次性把文件读取完成。可以先获取文件大小然后再读取

file.seekp(0,ios::end);
int64_t len = file.tellp();   // 获取文件大小
file.seekp(0,ios::beg);

char* buf = new char[len + 1] {0};       //及其重要
file.read(buf, len);
cout << buf;

delete[] buf;
使用std::getline读取

如果想直接读取到std::string里面,则需要使用std::getline。

std::string buf;
std::getline(file, buf);
cout << buf;

这样读取只能读取一行,如果想要读取多行,则需要使用循环。

std::string buf;
while (!file.eof())
{
	std::getline(file, buf);
	cout << buf << endl;
}
写入文件
  • 如果想要追加写入文件,请添加打开模式ios::app

  • 如果想要二进制读写,请添加打开模式ios::binary

使用<<写入
使用write写入

打开模式

模式标记适用对象作用
ios::inifstream fstream打开文件用于读取数据。如果文件不存在,则打开出错。
ios::outofstream fstream打开文件用于写入数据。如果文件不存在,则新建该文件;如果文件原来就存在,则打开时清除原来的内容。
ios::appofstream fstream打开文件,用于在其尾部添加数据。如果文件不存在,则新建该文件。
ios::ateifstream打开一个已有的文件,并将文件读指针指向文件末尾(读写指 的概念后面解释)。如果文件不存在,则打开出错。
ios:: truncofstream打开文件时会清空内部存储的所有数据,单独使用时与 ios::out 相同。
ios::binaryifstream ofstream fstream以二进制方式打开文件。若不指定此模式,则以文本模式打开。
ios::in | ios::outfstream打开已存在的文件,既可读取其内容,也可向其写入数据。文件刚打开时,原有内容保持不变。如果文件不存在,则打开出错。
ios::in | ios::outofstream打开已存在的文件,可以向其写入数据。文件刚打开时,原有内容保持不变。如果文件不存在,则打开出错。
ios::in | ios::out | ios::truncfstream打开文件,既可读取其内容,也可向其写入数据。如果文件本来就存在,则打开时清除原来的内容;如果文件不存在,则新建该文件。

文件位置指针

istream 和 ostream 都提供了用于重新定位文件位置指针的成员函数。这些成员函数包括关于 istream 的 seekg(“seek get”)和关于 ostream 的 seekp(“seek put”)。

seekg 和 seekp 的参数通常是一个长整型。第二个参数可以用于指定查找方向。
查找方向:

  • ios::beg 默认的,从流的开头开始定位
  • ios::cur 从流的当前位置开始定位
  • ios::end 从流的末尾开始定位

案例

#include <iostream>
#include <fstream>
using namespace std;

struct Gril {
    int age;
    string name;
};

int main()
{
    Girl mygirl[3] = {18, "w", 19, "y", 10, "l"};
    
    // 打开文件
    fstream file("./test.txt", ios::in | ios::out | ios::binary | ios::trunc);
    if(!file) {
        cerr << "file open failed" << endl;
    }
    
    // 写入文件
    file.write((char*)mygirl, sizeof(mygirl));
    
    // 文件指针移动到开头
    file.seekg(ios::beg);  
    
    //读
    Girl temp[3];
    file.read((char*)temp, sizeof(temp));
        
    for(auto& it : temp) {
        cout << it.age << " " << it.name << endl;
    }
    
    file.close();
    
    return 0;
}

文件操作的一些函数

这张图是当时我学《C++ prime》这本书的时候在博客找的,我感觉还是很清晰的讲解了文件操作相关的函数

在这里插入图片描述

字符串流

在C语言中,我们使用sscanf和sprintf来对字符串进行格式化,格式控制非常不方便,在C++中有了更方便的操作。

使用头文件添加对字符串流的支持。

我感觉,这个最大的作用就是,格式化与反格式化

打开字符串流

stringstream stream(ios::out | ios::in);

如果支持格式化和反格式化,则需要指定打开模式ios:inios::out

stream << 1 <<" " << "234"s <<" "<< 5.20;

使用stream对象,把需要的数据全部格式化,这里每个数据之间用空格隔开,方便等会反格式化。(反格式化以空格为分割字符)

cout << stream.str()<<endl;

当然在反格式化之前,我们使用stream.str()查看已经格式化的数据

int a;
float b;
string s;

首先我们定义三个对象,来接受从stream中反格式化的数据。

stream >> a >> s >> b;
cout << a <<" " << s << " " << b << endl;  // 反格式化的意思就是,输出的时候按照不同的数据类型自动识别,不受输入影响

从string反格式化

stringstream对象还可以绑定一个string对象,直接对string进行操作。

string buf = "1 234 5.20";
stringstream stream(buf);

先准备一个string对象,然后构造stringstream,默认以可读可写方式打开。

int a;
float b;
string s;
stream >> a >> s >> b;
cout << a << " " << s << " " << b << endl;   // 反格式化

如果在反格式化之后需要写入内容,是写入不了的,需要调用stream.clear()对格式进行清除,代码如下:

// 清除操作
stream.clear();
stream << "@@" << " ##";
cout << stream.str();

如果这个时候像着追加继续写,则只需要在构造stringstream对象的时候,添加上ios::app以追加的模式写入即可,如下:

stringstream stream(buf,ios::app | ios::in | ios::out);   

重定向流

重定向流:我们一般输入输出一般都是在屏幕、键盘上操作,键盘输入,屏幕输出,重定向流就是可以指定输出位置,比如说输出到文件,不输出到屏幕

代码实重定向

C语言方式

C语言方式可以通过freopen函数实现:

freopen("in.txt","r",stdin);	//stdin重定向到in.txt
//...
freopen("CON","r",stdin);		//恢复重定向

freopen("out.txt","w",stdout);

freopen("CON","w",stdout);
C++方式

C语言方式可以通过cin.rdbuf函数实现:

fstream fin("in.txt");
streambuf* oldbuf = cin.rdbuf();
cin.rdbuf(fin.rdbuf());
//...
cin.rdbuf(oldbuf);

http://www.niftyadmin.cn/n/5688289.html

相关文章

vue3项目el-table表格行内编辑加输入框校验

核心点 1. el-form的model属性需要跟el-form-item的prop要对应 2. el-form的model属性绑定tableData 3. el-form-item的prop绑定字符串&#xff1a;scope.index.列名&#xff08;注意有个点&#xff09; 4. el-form-item需要单独设置rules属性 代码示例 <el-form :mod…

05.useIsomorphicEffect

在 React 应用开发中,特别是涉及到**服务器端渲染(SSR)**时,正确处理副作用是一个常见挑战。useIsomorphicEffect 钩子提供了一种智能的方式来在服务器端和客户端环境中使用适当的副作用钩子。这个自定义钩子可以帮助开发者避免与 SSR 相关的常见陷阱,提高应用的性能和可靠…

C语言 | Leetcode C语言题解之题451题根据字符出现频率排序

题目&#xff1a; 题解&#xff1a; #define HASH_FIND_CHAR(head, findint, out) HASH_FIND(hh, head, findint, sizeof(char), out) #define HASH_ADD_CHAR(head, intfield, add) HASH_ADD(hh, head, intfield, sizeof(char), add)struct HashTable {char key;int val;UT_ha…

C++-第三章收尾:友元、匿名对象和new

目录 第一节&#xff1a;友元 1-1.友元函数 1-2.友元类 第二节&#xff1a;匿名对象 第三节&#xff1a;编译器优化 3-1.构造拷贝->直接构造 3-2.构造拷贝拷贝->直接构造 第四节&#xff1a;new 下期预告&#xff1a; 第一节&#xff1a;友元 一个类可以有友元函数和…

VSCode开发Vue3+TS项目中遇到各种波浪线(诊断信息)

一、问题汇总 在使用Visual Studio Code&#xff08;VSCode&#xff09;开发Vue3 TypeScript项目时&#xff0c;会遇到各种波浪线错误&#xff08;诊断信息&#xff09;&#xff0c;这些问题或错误通常由以下几人原因引起的&#xff1a; 1.1 常见问题 1、typeScript配置问题…

electron出现乱码和使用cmd出现乱码

第一种出现乱码。这种可以通过chcp 65001&#xff0c;设置为utf-8的编码。第二种&#xff0c;是执行exec的时候出现乱码&#xff0c;这个时候需要设置一些编码格式&#xff0c;可以通过iconv-lite进行解决&#xff0c;这个方法是node自带的&#xff0c;所以不需要导入。使用方法…

MySQL 索引选择详解

✨MySQL 索引选择详解✨ 引言 在使用 MySQL 进行数据查询时&#xff0c;索引是提升性能的关键工具。通过合理选择和优化索引&#xff0c;可以显著加快查询速度&#xff0c;减少磁盘 I/O&#xff0c;进而提高数据库响应时间。然而&#xff0c;有时 MySQL 可能不会选择我们预期…

文章解读与仿真程序复现思路——高电压技术EI\CSCD\北大核心《适用于并联构网型储能系统的协调有功控制策略设计》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…