【C++】IO流-创新互联
目录
创新互联公司坚持“要么做到,要么别承诺”的工作理念,服务领域包括:成都网站设计、做网站、企业官网、英文网站、手机端网站、网站推广等服务,满足客户于互联网时代的盐边网站设计、移动媒体设计的需求,帮助企业找到有效的互联网解决方案。努力成为您成熟可靠的网络建设合作伙伴!一、C语言IO
二、C++IO
1.标准IO
2.文件IO
3、字符串IO
总结
一、C语言IO
C语言中我们用到的最频繁的输入输出方式就是scanf ()与printf()。 scanf(): 从标准输入设备(键 盘)读取数据,并将值存放在变量中。printf(): 将指定的文字/字符串输出到标准输出设备(屏幕)。
对输入输出缓冲区的理解: 1.可以屏蔽掉低级I/O的实现,低级I/O的实现依赖操作系统本身内核的实现,所以如果能够屏蔽这部分的差异,可以很容易写出可移植的程序。 2.可以使用这部分的内容实现“行”读取的行为,对于计算机而言是没有“行”这个概念,有了这部分,就可以定义“行”的概念,然后解析缓冲区的内容,返回一个“行”。二、C++IO 1.标准IOC++IO具有一个庞大的体系
我们发现C++IO体系十分的复杂,甚至出现了菱形继承,这种十分不推荐的继承
istream,ostream继承了ios,iostream又继承了istream,ostream
C++编译之后,在操作系统中运行,变成了一个进程,操作系统会默认打开三个流,标准输入,标准输出,标准错误,在C++中对应为cin, cout, cerr
从上图可以看出,cout、cerr、clog是ostream类的三个不同的对象,因此这三个对象现在基本没有区别,只是应用场景不同。cin是默认以空格或者换行符为间隔的,它主要是使用>>(流提取操作符)
同时我们也可以自己实现>>操作符的重载,使其能够与内置类型一样可以直接通过cin >>对象
标准IO经常使用就不过多废话,主要说明下面的一个问题
void test_standIO()
{
int n = 0;
while(cin >>n)
{
cout<< n<< endl;
}
}
我们先简单的看一下这个代码,它是循环的输入到n中,并且不断地打印n
那么如何停止呢?
方法一,ctrl + c
原理是给进程发信号,让操作系统结束掉进程,同时刷新缓冲区,使最后的数据打印出来
方法二,ctrl + z + enter
原理:ctrl + z 是流结束的标志
这个代码的原理是什么?
我们看到operator>>()返回的是istream对象的引用,它是一个对象,C++对象是不能进行布尔比较的,这到底是什么情况?
原因是,它发生了隐式类型转换
他隐式类型转换为bool类型,这样就可以进行比较了
operator bool 库中实现的比较怪异,他并没有返回值
2.文件IO C++根据文件内容的数据格式分为二进制文件和文本文件。采用文件流对象操作文件的一般步骤: 1. 定义一个文件流对象 ifstream ififile(只输入用) ofstream ofifile(只输出用) fstream iofifile(既输入又输出用) 2. 使用文件流对象的成员函数打开一个磁盘文件,使得文件流对象和磁盘文件之间建立联系 3. 使用提取和插入运算符对文件进行读写操作,或使用成员函数进行读写 4. 关闭文件我们先来说明二进制文件读写
二进制读写的内容在内存中是如何存储的,它就如何写到磁盘文件中
优点:快
缺点:因为存储的都是二进制,写出去的内容一般不可见,字符串因为有编码,可以在磁盘文件中直接看到
struct ServerInof
{
char buffer[128];
int _port;
};
struct ConfigManager
{
ConfigManager(const char* filename = "server.config")
:_filename(filename)
{}
void WriteBin(const ServerInof& info)
{
ofstream ofs(_filename, ios_base::out | ios_base::binary);
ofs.write((char*)&info, sizeof info);
}
void ReadBin(ServerInof& info)
{
ifstream ifs(_filename, ios_base::in | ios_base::binary);
ifs.read((char*)&info, sizeof info);
}
private:
string _filename; // 配置文件
};
void test_fileIO()
{
ServerInof info;
// string msg("Hello World");
// strcpy(info.buffer, msg.c_str());
// info._port = 888;
ConfigManager cfm;
//cfm.WriteBin(info);
cfm.ReadBin(info);
string str = info.buffer;
cout<< info.buffer<< endl;
cout<< info._port<< endl;
}
我们先打开文件,然后将数据以二进制方式保存到文件
然后我们打开文件
内部就是一些二进制数据,我们无法直接识别
然后从文件中读取
结果是正确的
不过二进制读写是有十分大的局限性的,它并不适用于有深拷贝对象的场景
二进制方式读写,它直接存储的是地址,可能会有对齐等等非有效数据
既然它存储的是地址,那么在深拷贝的情况下可能会有野指针的问题
我们将上面的ServerInof中的字符数组,改成string,再次运行
然后读取数据
直接报了一个段错误,出现了野指针问题
所以二进制方式并不适合具有深拷贝的类
文本方式读写文件
文本读写:对象数据序列化字符串写出来,读回来也是字符串,反序列化转成对象数据
优点:可以看见写出去是什么
缺点:存在一个转换过程,要慢一些
struct ConfigManager
{
ConfigManager(const char* filename = "server.config")
:_filename(filename)
{}
void WriteBin(const ServerInof& info)
{
ofstream ofs(_filename, ios_base::out | ios_base::binary);
ofs.write((char*)&info, sizeof info);
}
void ReadBin(ServerInof& info)
{
ifstream ifs(_filename, ios_base::in | ios_base::binary);
ifs.read((char*)&info, sizeof info);
}
void WriteText(const ServerInof& info)
{
ofstream ofs(_filename, ios_base::out);
//一个对象一个对象的读
ofs.write(info.buffer.c_str(), info.buffer.size());
ofs.put('\n');
string str = to_string(info._port);
ofs.write(str.c_str(), str.size());
}
void ReadText(ServerInof& info)
{
ifstream ifs(_filename, ios_base::in);
char buffer[128];
ifs.getline(buffer, sizeof buffer);
info.buffer = buffer;
ifs.getline(buffer, sizeof buffer);
info._port = stoi(buffer);
}
private:
string _filename; // 配置文件
};
void test_fileIO2()
{
ServerInof info;
//info.buffer = "Hello World";
//info._port = 888;
ConfigManager cfm;
//cfm.WriteText(info);
cfm.ReadText(info);
cout<< info.buffer<< endl;
cout<< info._port<< endl;
}
上面的操作十分的不方便,我们可以采用与标准IO一样,cin,cout如何使用,文件IO流就如何使用
我们可以简化上面的代码
void WriteText(const ServerInof& info)
{
ofstream ofs(_filename, ios_base::out);
//一个对象一个对象的读
// ofs.write(info.buffer.c_str(), info.buffer.size());
// ofs.put('\n');
// string str = to_string(info._port);
// ofs.write(str.c_str(), str.size());
ofs<< info.buffer<< endl;
ofs<< info._port<< endl;
}
void ReadText(ServerInof& info)
{
ifstream ifs(_filename, ios_base::in);
// char buffer[128];
// ifs.getline(buffer, sizeof buffer);
// info.buffer = buffer;
// ifs.getline(buffer, sizeof buffer);
// info._port = stoi(buffer);
ifs >>info.buffer >>info._port;
}
3、字符串IO
在C语言中,如果想要将一个整形变量的数据转化为字符串格式,如何去做?
1. 使用itoa()函数
2. 使用sprintf()函数
但是两个函数在转化时,都得需要先给出保存结果的空间,那空间要给多大呢,就不太好界定,而且转化格式不匹配时,可能还会得到错误的结果甚至程序崩溃。 我们以下面的简单代码讲解
class Date
{
friend istream& operator>>(istream& in, Date& d);
friend ostream& operator<<(ostream& out, const Date& d);
public:
Date(int year = 1970, 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<< "日";
}
struct ChatInfo
{
string _name;
int _id;
Date _date;
string _msg;
};
void test_stringIO()
{
//发送数据
ChatInfo ch = {"张三", 1294268442, {2022, 11, 30}, "一起去看电影"};
stringstream oss;
oss<< ch._date<< endl;
oss<< ch._name<< endl;
oss<< ch._id<< endl;
oss<< ch._msg<< endl;
string str = oss.str();
cout<< str<< endl;
//解析数据
stringstream iss(str);
ChatInfo rinfo;
iss >>rinfo._date;
iss >>rinfo._name;
iss >>rinfo._id;
iss >>rinfo._msg;
cout<<"-----------------------------"<< endl;
cout<< rinfo._date<< endl;
cout<< rinfo._name<< rinfo._id<< endl;
cout<< rinfo._msg<< endl;
cout<<"-----------------------------"<< endl;
}
这里走的还是C++ 流提取和流插入的操作与标准IO,文件IO的操作一模一样,并且它们的接口都类似
总结
以上就是今天要讲的内容,本文仅仅简单介绍了C++IO
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
文章标题:【C++】IO流-创新互联
文章URL:http://hbruida.cn/article/ddjios.html