欢迎来到C++专栏~~IO流

(꒪ꇴ꒪(꒪ꇴ꒪ ),我是Scort目前状态:大三非科班啃C++中博客主页:张小姐的猫~江湖背景快上车,握好方向盘跟我有一起打天下嘞!送给自己的一句鸡汤樂:真正的大师永远怀着一颗学徒的心作者水平很有限,如果发现错误,可在评论区指正,感谢欢迎持续关注!

文章目录

欢迎来到C++专栏~~IO流一. C语言的输入与输出二. 流是什么三. C++IO流C++标准IO流✨C++文件IO流⚡以二进制的形式操作文件⚡以文本的形式操作文件⚡使用>>和<<对文件进行操作

四. stringstream的简单介绍

写在最后

一. C语言的输入与输出

C语言中我们用到的最频繁的输入输出方式就是scanf ()与printf()

scanf(): 从标准输入设备(键盘)读取数据,并将值存放在变量中printf(): 将指定的文字/字符串输出到标准输出设备(屏幕)

C语言借助了相应的缓冲区来进行输入与输出

对输入输出缓冲区的理解:

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

二. 流是什么

“流”即是流动的意思,是物质从一处向另一处流动的过程,是对一种有序连续且有方向性的数据的抽象描述。

C++流是指信息从外部输入设备(如键盘)向计算机内部(如内存)输入和从内存向外部输出设备(显示器)输出的过程。这种输入输出的过程被形象的比喻为“流”

流的特性:有序连续、具有方向性

三. C++IO流

C++系统实现了一个庞大的类库,其中ios为基类,其他类都是直接或间接派生自ios类

从上图可以看出,cout、cerr、clog都是由ostream类实例化出的三个不同的对象,因此这三个对象基本没什么区别,只是应用场景不同。

C++标准IO流

C++标准库提供了4个全局流对象(cin、cout、cerr、clog):

使用cout进行标准输出,即数据从内存流向控制台(显示器)使用cin进行标准输入,即数据通过键盘输入到程序中使用cerr进行标准错误的输出使用clog进行日志的输出

注意: 1、在使用cin、cout时必须要包含iostream文件,并引入std标准命名空间。

#include //包含iostream文件

using namespace std; //引入std标准命名空间

int main()

{

int a = 0;

cin >> a;

cout << a << endl;

return 0;

}

或者指定cout和cin所属的命名空间

#include //包含iostream文件

int main()

{

int a = 0;

std::cin >> a; //使用时指定所属命名空间

std::cout << a << std::endl; //使用时指定所属命名空间

return 0;

}

2、cin为缓冲流。键盘输入的数据保存在缓冲区中,当要提取时,是从缓冲区中提取。如果一次输入过多,则多余的数据会留在缓冲区以供之后提取,如果输入错了,必须在回车之前进行修改,回车键按下就无法进行修改了,只有把输入缓冲区中的数据取完后,才会要求输入新的数据

例如,对于以下代码,若在第一次输入时便以空格为分隔输入了两个数据,则在下一次需要提取数据的时候就直接从缓冲区进行提取

#include

using namespace std;

int main()

{

int a = 0, b = 0;

cin >> a; //输入:10 20

cout << a << endl;

cin >> b; //直接从输入缓冲区提取

cout << b << endl;

return 0;

}

3、 输入的数据类型必须与要提取的数据类型一致,否则出错。出错只是在流的状态字state中对应位置位(置1),程序继续

4、空格和回车都可以作为数据之间的分隔符,所以多个数据可以在一行输入,也可以分行输入。但如果是字符型和字符串,则空格无法用cin输入,字符串中也不能有空格,回车符也无法读入。 例如,我们使用cin无法将含空格的字符串"hello world"输入到string对象中。

#include

#include

using namespace std;

int main()

{

string s;

cin >> s; //输入:"hello world"

cout << s << endl; //输出:"hello"

return 0;

}

对于含有空格的字符串,我们需要使用getline函数进行读取,因为getline函数只有遇到’\n’才会停止读取。

#include

#include

using namespace std;

int main()

{

string s;

getline(cin, s); //输入:"hello world"

cout << s << endl; //输出:"hello world"

return 0;

}

5、cin和cout可以直接输入和输出内置类型的数据。因为标准库已经将所有内置类型的输入和输出进行了重载。

>>的运算符的重载: <<的运算符的重载:

6、对于自定义类型,如果要支持cin和cout的标准输入输出,则需要对<<和>>进行重载。 例如,对于下面简单实现的日期类,在对<<和>>进行重载后就能够支持cin和cout的输入输出了。

#include

using namespace std;

class Date

{

friend istream& operator>>(istream& in, Date& d);

friend ostream& operator<<(ostream& out, const Date& d);

public:

Date(int year = 2021, int month = 1, int day = 1)

:_year(year)

, _month(month)

, _day(day)

{}

private:

int _year;

int _month;

int _day;

};

//对>>进行重载

istream& operator>>(istream& in, Date& d)

{

in >> d._year >> d._month >> d._day;

return in;

}

//对<<进行重载

ostream& operator<<(ostream& out, const Date& d)

{

out << d._year << "-" << d._month << "-" << d._day;

return out;

}

int main()

{

Date d;

cin >> d; //输入:2021 9 20

cout << d << endl; //输出:2021-9-20

return 0;

}

7、输入多个值,默认就是用空格或者换行分割的

int year, month, day;

cin >> year >> month >> day;

scanf("%d%d%d", &year, &month, &day);

//scanf("%d %d %d", &year, &month, &day);//不需要去加空格

如果输入的数值严格是20221128,可以用substr(),进行断句

//20230219

string str;

cin >> str;

year = stoi(str.substr(0, 4));

month = stoi(str.substr(4, 2));

day = stoi(str.substr(6, 2));

8、在线OJ中的输入和输出

某些在线OJ题目是有多组测试用例对我们编写的代码进行测试的,对于这种题目,C语言通常采用的解决方式如下:

while (scanf("%d", &a) != EOF)

{

//...

}

而在C++当中,我们一般采用的解决方式如下:

while (cin >> a)

{

//...

}

C++中是运用了operator bool

✨C++文件IO流

C++根据文件内容的数据格式将文件分为二进制文件和文本文件,采用文件流对象操作文件的一般步骤如下: 1、定义一个文件流对象。 操作文件的类有以下三个:

类对应操作场景ofstream只写ifstream只读fstream读和写

2、文件常见的打开方式如下:

打开方式功能in以读的方式打开文件out以写的方式打开文件binary以二进制方式对文件进行操作ate输出位置从文件的末尾开始app以追加的方式对文件进行写入trunc先将文件内容清空再打开文件

3、对文件进行提取和插入操作的常用成员函数:

成员函数功能put插入一个字符到文件write插入一段字符到文件get从文件提取字符readreadtellg获取当前字符在文件当中的位置seekg设置对文件进行操作的位置>>运算符重载将数据形象地以“流”的形式进行输入<<运算符重载将数据形象地以“流”的形式进行输出

3、关闭文件

⚡以二进制的形式操作文件

二进制的读写:在内存中如何存储,就如何写到磁盘文件中 优点:快 缺点:写出去的内容看不见

以二进制的形式对文件进行写入操作:

//配置文件

struct ServerInfo

{

char _address[32]; //ip

int _port; //端口

};

//配置管理器

struct ConfigManager

{

public:

ConfigManager(const char* filename = "test.txt")

:_filename(filename)

{}

//写

void WriteBin(const ServerInfo& info)

{

ofstream ofs(_filename, ios_base::out | ios_base::binary);

ofs.write((char*)&info, sizeof(info));

}

//读

void ReadBin(ServerInfo& info)

{

ifstream ifs(_filename, ios_base::in | ios_base::binary);

ifs.read((char*)&info, sizeof(info));

}

private:

string _filename; // 配置文件

};

int main()

{

//二进制写

ServerInfo winfo = { "192.0.0.1", 12138 };

ConfigManager cm;

cm.WriteBin(winfo);

//二进制读

ServerInfo rinfo;

ConfigManager cm;

cm.ReadBin(rinfo);

cout << rinfo._address << endl;

cout << rinfo._port << endl;

}

此处要注意:

struct ServerInfo

{

//char _address[32]; //ip

string _address; //此处用string会更好

int _port; //端口

};

但会引发一个问题:打印出来的是乱码 其原因是:数据存在堆中,地址会更改

所以二进制读写的时候不适合用string,更多用的是数组来解决

文本读写就不限制,二者都可以用

⚡以文本的形式操作文件

文本读写:对象数据序列化字符串写出来,堵回来也是:字符串反序列化转成对象数据

优点:可以看得见写出去的是什么 缺点:存在一个转换的过程

//文本写

void WriteText(const ServerInfo& info)

{

//c_str() : 将C++的string转化为C的字符串数组,c_str()生成一个const char *指针,指向字符串的首地址

ofstream ofs(_filename, ios_base::out);

ofs.write(info._address.c_str(), info._address.size());

ofs.put('\n');

const string str = to_string(info._port);

ofs.write(str.c_str(),str.size());

}

//文本读

void ReadText(ServerInfo& info)

{

ifstream ifs(_filename, ios_base::in | ios_base::binary);

char buff[128];

ifs.getline(buff, 128);

info._address = buff;

ifs.getline(buff, 128);

info._port = stoi(buff);

}

int main()

{

//文本写

ServerInfo winfo = { "192.0.0.1", 111111};

ConfigManager cm;

cm.WriteText(winfo);

//文本读

ServerInfo rinfo;

ConfigManager cm;

cm.ReadText(rinfo);

cout << rinfo._address << endl;

cout << rinfo._port << endl;

}

⚡使用>>和<<对文件进行操作

使用>>和<<运算符对文件进行读写操作,会变得很简单,也很形象 如果自定义类型也支持流插入、提取的重载

//对文件进行写入操作

void WriteTest(const ServerInfo& info)

{

ofstream ofs(_filename, ios_base::out);

ofs << info._address <

ofs << info._port <

ods << info._Date <

}

对文件的读取:

//对文件进行读取操作

void ReadFile()

{

ifstream ifs("data.txt"); //定义文件流对象,并打开文件

char data[100];

ifs >> data; //文件数据“流入”字符串data

ifs.close(); //关闭文件

}

四. stringstream的简单介绍

在C语言中,我们若是想要将一个整型变量的数据转化为字符串格式,有以下两种方法:

使用itoa函数进行转化

int a = 10;

char arr[10];

itoa(a, arr, 10); //将整型的a转化为十进制字符数字存储在字符串arr当中

使用sprintf函数进行转化

int a = 10;

char arr[10];

sprintf(arr, "%d", a); //将整型的a转化为字符串格式存储在字符串arr当中

虽然itoa函数和sprintf函数都能完成转化,但是在两个函数在转化时,都需要先给出保存结果的空间,而空间的大小是不太好界定的,除此之外,转化格式不匹配时,可能还会得到错误的结果甚至程序崩溃。

在C++中,我们可以使用stringstream类对象来避开此问题。在程序当中如果想要使用stringstream,必须要包含头文件sstream。在该头文件下,有三个类:

此处重点讲解:序列化和反序列化结构数据

struct ChatInfo

{

string _name; // 名字

int _id; // id

};

int main()

{

// 结构信息序列化为字符串

ChatInfo winfo = { "张三", 135246};

ostringstream oss;

oss << winfo._id << endl;

oss << winfo._name << endl;

string str = oss.str();

cout << str << endl;

//网络传输str ~

//反系列化

ChatInfo rInfo;

istringstream iss(str);

iss >> rInfo._id;

iss >> rInfo._name;

cout << "-------------------------------------------------------"<< endl;

cout << "姓名:" << rInfo._name << "(" << rInfo._id << ") "<< endl;

cout << "-------------------------------------------------------"<< endl;

return 0;

}

写在最后

好文阅读

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。