- 本人的LeetCode账号:魔术师的徒弟,欢迎关注获取每日一题题解,快来一起刷题呀~
- 本人Gitee账号:路由器,欢迎关注获取博客内容源码。
文章目录一、C语言的输入输出
二、C++的输入输出流
- 1 流是什么
- 2 C++的标准IO流
- 3 C++的文件IO流
- 3 C++的字符串IO流
一、C语言的输入输出
C语言主要使用scanf
和printf
与输入输出设备交互,大概是这样的:
二、C++的输入输出流 1 流是什么
“流”即是流动的意思,是物质从一处向另一处流动的过程,是对一种有序连续且具有方向性的数据( 其单位 可以是bit,byte,packet )的抽象描述。
C++流是指信息从外部输入设备(如键盘)向计算机内部(如内存) 输入和从内存向外部输出设备(显示器)输出的过程。
这种输入输出的过程被形象的比喻为“流”。
它的特性是:有序连续、具有方向性
为了实现这种流动,C++定义了I/O标准类库,这些每个类都称为流/流类,用以完成某方面的功能。
C++的这些cin cout
等都是一些全局对象,关系如下,ios
是其基类,它们之间有继承的关系。
之前我们说过,cout
和cin
能自动识别类型的原因是因为它们做了运算符重载,同时这些运算符有构成了函数重载。
所以自定义类型需要我们自己做函数重载才可以用。
cin cout效率提升
ios::sync_with_stdio(false);
这条语句可以把cin
和scanf
、cout
和printf
的同步关掉,可以提升cin
的速度,不过这时cin
和scanf
混用就会出错。
没有这条语句时,cin cout
为了保证混用printf
和scanf
时文件指针不混乱做了很多工作,所以速度要慢,关掉速度就会快很多。
读取一行
C语言读取一行,可以用fgets
,C++可以用getline
。
cin cout
相比scanf
和printf
的优势就在于自定义类型对象在重载后可以直接使用<<
和>>
输入输出,不比每次都要自己用scanf
和printf
组合。
多组测试用例
C语言写法:
while (scanf("", ) != EOF)
因为scanf
会返回读取的个数,当读取的个数是0的时候,就结束了。
C++写法:
while (cin >> )
这里判断的表达式是判断的cin
这个istream
对象,按理说不应该啊,我们之前值接触过整形和布尔值做逻辑判断,这里怎么对象也能做逻辑判断了,是因为类型运算符重载,当用istream
对象进行逻辑判断时,它就会调用这个类型运算符重载,使其返回一个布尔值。
我们的一个简单测试:
class B
{
public:
B(int b = 0) : _b(b)
{}
operator bool()
{
return _b != 0;
}
private:
int _b;
};
int main()
{
B b1(11);
if (b1)
{
cout << "隐式类型转换一样的operator bool()" << endl;
}
return 0;
}
所以上面的原理就是在istream
类内部有一个标志符,当读取结束的时候,就会给这个标志符该为false
,然后operator bool()
返回这个标志符作为真假性即可。
进一步测试:
class B
{
public:
B(int b = 0) : _b(b)
{}
operator bool()
{
return _b != 0;
}
friend istream& operator>>(istream& in, B& b);
friend ostream& operator<<(ostream& out, B& b);
private:
int _b;
};
istream& operator>>(istream& in, B& b)
{
in >> b._b;
return in;
}
ostream& operator<<(ostream& out, B& b)
{
out << b._b;
return out;
}
int main()
{
B b1(11);
while (b1)
{
cin >> b1;
cout << b1 << endl;
}
return 0;
}
3 C++的文件IO流
假如我们要把如下结构的对象写入文件中:
struct ServerInfo
{
char _ip[32]; // ip
int _port; // 端口
};
使用C语言的话,首先我们需要用fopen
和fclose
打开和关闭文件,文件的读写有两种方式,二进制读写可以使用fwrite
和fread
作为接口,直接写出内存中你的数据是怎么二进制存储的。
还有一种写字符串来读写文件,接口为fputs
和fgets
打印接收一行,fprintf
和fscanf
来格式化字符串读写。
写:
void testC_bin()
{
ServerInfo info = { "127.0.0.1", 80 };
FILE* pf = fopen("test.bin", "wb");
assert(pf);
fwrite(&info, sizeof(info), 1, pf);
fclose(pf);
}
读:
void testC_R_bin()
{
ServerInfo info;
FILE* pf = fopen("test.bin", "rb");
assert(pf);
fread(&info, sizeof(info), 1, pf);
cout << info._ip << ' ' << info._port << endl;
fclose(pf);
}
二进制读写比较简单,但缺陷是写出去的东西文件中看不见。
字符型读写测试:
void testC_W_S()
{
ServerInfo info = { "127.0.0.1", 80 };
FILE* pf = fopen("test.txt", "w");
assert(pf);
fprintf(pf, "%s %d", info._ip, info._port);
fclose(pf);
}
void testC_R_S()
{
ServerInfo info;
FILE* pf = fopen("test.txt", "r");
assert(pf);
fscanf(pf, "%s %d", info._ip, &info._port);
printf("%s %d\n", info._ip, info._port);
fclose(pf);
}
注意fscanf
和scanf
类似,对多个数据,它们都以' '
或\n
区分。
我们用C++的风格玩一下,包头文件
。
C++中,ofstream
是写文件流的类:
构造函数中的模式类型:
这里是用比特位表示状态,和Linux
中的系统调用状态类似,可以|
来把状态弄到一起。
它的写的成员函数:
框架:
// 管理文件名
class ConfigManager
{
public:
ConfigManager(const string& str): _filename(str)
{}
void writeBin(const ServerInfo& info)
{
ofstream of(_filename.c_str(), ios_base::binary | ios_base::out);
of.write((const char*)(&info), sizeof(info));
}
void readBin(ServerInfo& info)
{
ifstream of(_filename.c_str(), ios_base::binary | ios_base::in);
of.read((char*)(&info), sizeof(info));
}
void writetxt(const ServerInfo& info)
{
// 默认参数就是文件读写
ofstream of(_filename.c_str());
of << info._ip << ' ' << info._port;
}
void writetxt(ServerInfo& info)
{
// 默认参数就是文件读写
ifstream ifs(_filename.c_str());
ifs >> info._ip >> info._port;
}
private:
string _filename;
};
二进制写:
void testCPPWbin()
{
ServerInfo info = { "192.0.0.1", 80 };
ConfigManager con("myconfig.bin");
con.writeBin(info);
}
二进制读:
void testCPPRbin()
{
ServerInfo info;
ConfigManager con("myconfig.bin");
con.readBin(info);
cout << info._ip << ' ' << info._port << endl;
}
文本写:
void testCPPWtxt()
{
ServerInfo info = { "191.0.0.1", 80 };
ConfigManager con("myconfig.txt");
con.writetxt(info);
}
文本读:
void testCPPRtxt()
{
ServerInfo info;
ConfigManager con("myconfig.txt");
con.readtxt(info);
cout << info._ip << ' ' << info._port << endl;
}
二进制读写和C类似,不过文本读写可以支持operator >>
和operator <<
,可以对自定义类型重载这些运算符,然后就可以像cout
、cin
那样进行文本读写。
对自定义类型,这里需要去掉const
,不知道为啥。
class Date
{
public:
Date(int year = 2000, int month = 1, int day = 1)
: _year(year), _month(month), _day(day)
{}
friend ofstream& operator<<(ofstream& out, Date& d);
private:
int _year;
int _month;
int _day;
};
ofstream& operator<<(ofstream& out, Date& d)
{
out << d._year << ' ' << d._month << ' ' << d._day << endl;
return out;
}
void writetxt(ServerInfo& info)
{
// 默认参数就是文件读写
ofstream of(_filename.c_str());
of << info._ip << ' ' << info._port << ' ';
of << info._d;
}
3 C++的字符串IO流
头文件
。
ostringstream
:把一个自定义结构中的内容读成一个字符串,类似sprintf
。
它支持operator<<
,可以从结构中把内容直接转字符串,注意分割,如果要获得转成的字符串,用.str()
即可:
istringstream
:把一个字符串中的内容一部分一部分读取出来,类似sscanf
。
它也支持operator>>
,可以从字符串中把内容读出来,注意需要分隔符。
在网络编程中,可以用这两个东西来完成序列化和反序列化的任务。
一个测试:
class Date
{
public:
Date(int year = 2000, int month = 1, int day = 1)
: _year(year), _month(month), _day(day)
{}
friend ofstream& operator<<(ofstream& out, Date& d);
friend ostringstream& operator<<(ostringstream& out, Date& d);
friend ostream& operator<<(ostream& out, Date& d);
friend istringstream& operator>>(istringstream& sin, Date& d);
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& out, Date& d)
{
out << d._year << ' ' << d._month << ' ' << d._day;
return out;
}
ofstream& operator<<(ofstream& out, Date& d)
{
out << d._year << ' ' << d._month << ' ' << d._day << endl;
return out;
}
ostringstream& operator<<(ostringstream& out, Date& d)
{
out << d._year << ' ' << d._month << ' ' << d._day << endl;
return out;
}
istringstream& operator>>(istringstream& sin, Date& d)
{
sin >> d._year >> d._month >> d._day;
return sin;
}
struct Personinfo
{
string _name;
int _age;
Date _d;
};
int main()
{
Personinfo p = { "路由器", 20 };
ostringstream oss;
oss << p._name << " " << p._age << " ";
oss << p._d;// 这里要换行 不知道为什么
cout << oss.str() << endl;
string tmp = oss.str();
istringstream iss(tmp);
Personinfo p1;
iss >> p1._name >> p1._age;
iss >> p1._d;
cout << p1._name << '*' << p1._age << '+' << p1._d << endl;
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)