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

本专栏目的

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

前言

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

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);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值