1.回忆C语言的IO流
getchar() //字符输入函数
putchar() //字符输出函数
fgetc()/getc() //字符输入函数
fputc()/putc() //字符输入函数
fgets()/gets() //文本行输出函数
fputs()/puts() //文本行输出函数
printf()/scanf() //标准格式化输入输出函数
fprintf()/fscanf() //所有流的输入输出函数
fread()/fwrite() //文本的输入输出
注:上述函数用法总结我的另一篇博客:https://blog.csdn.net/hansionz/article/details/80884217
在C语言中,我们使用最频繁的函数是printf、scanf
。C语言的IO函数是借助缓冲区
实现的。缓冲区的读写速度较快
,设备和代码都能很快的从其中复制数据和写入数据
,从而完成IO
操作。
缓冲区的缓冲方式分为三类:
- 全缓冲:当缓冲区
写满
之后才刷新出来 - 行缓冲:缓冲区遇到
换行符
既刷新 - 无缓冲:写入的数据
立即
被刷新出来
输入/输出缓冲区存在的原因:
- 可以屏蔽掉
低级I/O
的实现,低级I/O的实现依赖操作系统
本身内核的实现,所以如果能够屏蔽这部分的差异,可以很容易写出可移植
的程序 - 可以使用这部分的内容实现
“行”
读取的行为,对于计算机
而言是没有“行”
这个概念。有了这缓冲区
,就可以定义“行”
的概念,然后按“行”
解析缓冲区的内容
2.流的概念
“流”即是流动
的意思,是物质从一处
向另一处
流动的过程,是对一种有序连续且具有方向性
的数据的抽象描述
。C++
流是指信息从外设
向计算机内部(如内存) 输入或者从内存
向外设
输出的过程。这种输入输出的过程被形象的比喻为“流”
。流的特点是连续性的,具有方向性
。C语言
的流是基于缓冲区
实现的,输入输出的区别在于方向不同和对数据的操作不同。
流可以分为两种:
- 文本流:在缓冲区中读出和写入时是基于
ASCII
或Unicode
字符编码的。写入缓冲区的最大长度规定为254
个字符。在文本文件结束时规定以一个回车符
和换行符
结尾,在写入缓冲区时,会将\n
转换为回车换行
符,在从缓冲区中读取出数据时,就会将回车换行
符转换为换行符
。 - 二进制流:二进制的流在向缓冲区中
写入或读出
文件时,不进行字符的转换,直接从设备或文件中读取,在这个过程中不发生任何改变
,原先是什么样子,读取之后还是什么样子,它是基于二进制数字。
对于每一个ANSI C
程序⽽而言,至少打开三个流
:标准输入(stdin)、标准输出(stdout)、标准错误(stderr),他们都是一个指向FILE
结构的指针。
3.C++中的IO流
为了实现数据的流动,C++
定义了I/O
标准类库,这些每个类都称为流/流类
,用以完成某方面的功能。C++
的IO操作编译时会对类型严格
的检查,所以C++的IO是类型安全
的,而C语言中的输入输出并不是
类型安全的
C++中三种IO操作:标准IO 文件IO 串IO。
- 标准IO:兼容了
C
中的标准的输入输出
,以键盘和屏幕为操作对象,从键盘输入或从屏幕输出 - 文件IO:以
磁盘
文件为输入输出的对象,数据在磁盘中写入和读出 - 串IO:对内存中
指定的空间
进行输入输出。通常指定一个字符数组作为存储空间(实际上可以利用该空间存储任何信息)。这种输入和输出称为字符串输入输出
C++系统
实现了一个庞大的类库,其中ios
为基类,其他类都是直接或间接派生自ios类
。这些类可以对基本类型
进行输入输出,也可以对自定义的类型
进行输入输出,这些类体现了C++标准IO库的可扩展性
。
C++在类库中定义了四个全局流的对象:
- cin : 标准
输入
流,对应键盘 - cout:标准
输出
流,对应显示器 - clog:标准输出
错误
流,对应显示器 - cerr:标准输出
错误
流,对应显示器
注意:
- 使用
cin
输入的时候,键盘输入的数据保存在缓冲区
中,当要提取时,是从缓冲区中拿。如果一次输入过多,会留在那儿慢慢用。如果输入错了,必须在回车之前
修改,如果回车键按下
就无法修改。只有把输入缓冲区中的数据取完后,才要求输入新的数据。 - 输入的
数据类型
必须与要提取的数据类型一致
,否则会报错。出错只是在流的状态字state
中对应位置1
,程序继续执行。 空格和回车
都可以作为数据之间的分格符
,所以多个数据可以在一行输入,也可以分行输入。但如果是字符型和字符串
,则空格(ASCII码为32)
无法用cin
输入,字符串中也不能有空格
。回车符
也无法读入,因为遇到回车说明输入结束。
4.文件流对象
C++
中根据文件内容
的数据格式分为二进制文件
和文本文件
,在类库中实现了对文件操作
的类。
fstream库中有三个类流:
- ifstream :支持从磁盘文件
输入(istream)
- ofstream 支持向磁盘文件
输出(ostream)
- fstream 支持从磁盘文件
输入和输出
在使用时,我们需要创建一个流对象
来进行操作,cin cout
等流对象是在iostream
中创建好的(在上边的类图
中可以看到)。
ifstream ifile //输入使用
ofstream ofile //输出使用
fstream iofile //输入输出使用
C++
对于文件操作和C语言
一样,在类中有关于打开,关闭,写入,和读出
的对文件操作的成员函数。
- 打开文件:将一个
流对象
与一个文件
相关联
//通过构造函数
std::ofstream ofile("test1.txt",std::ofstream::out);
参数:文件名和请求标志位
//使用成员函数open
std::ofstream ofile;
ofile.open("test1.txt",std::ofstream::out)
如果该文件已经打开,open
会调用失败。
请求标志位如下:
标志 | 功能 |
---|---|
in(input) | 打开文件读,内部流缓冲区支持输入操作 |
out(output) | 文件打开供写入,内部流缓冲区支持输出操作 |
binary | 执行二进制操作 |
app()append | 追加,所有的操作都发生在文件的末尾 |
ate(at end) | 输出位置在文件的末尾 |
trunc(trucate) | 打开文件之前存于文件之中的内容都会被丢弃 |
注:文件打开默认位文本文件权限标志位之间可以使用|
进行组合。ofstream
的流对象默认是out
。ifstream
默认是in
所以可以不用写。
- close:断开当前
文件
与流对象
之间的关联
ofile.colse();
如果当前流对象没有打开文件,则调用时就会失败。
- 在对文本文件进行操作时可以用
插入 >> 运算符
和提取 << 运算符
进行
ofstream ofile("test1.txt",std::ofstream::out);
ofile << "sdasdas"; //表示向文件中输入一个数,输出到流上
char a[1024];
ifstream ifile("test1.txt",std::ifstream::in);
ifile >> a; //读出文件的数据,输入到流中
- write:
ofstream
类中提供了write
成员函数,用于向文件中写入数据
ostream& write (const char* s, streamsize n);
- read:
ifstream
类中提供了read
成员,用于从文件中读取数据
istream& read (char* s, streamsize n);
对二进制
读写时,我们采用write
和read
成员函数进行操作。
- 其他的成员函数入
put() \ get()
istream& get (char& c); //支持从流中读取单个字符
ostream& put (char c); //将单个字符插入到流中
使用文件IO流用文本及二进制方式读写配置文件:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
class ConfigInfo
{
public:
int port;
char ip[32];
};
class ConfigManager
{
public:
ConfigManager(const char* file = "test.config")
:configfile(file)
{}
//二进制读写
void WriteBinary(const ConfigInfo& info)
{
ofstream ofile(configfile, ofstream::binary | ofstream::out);
ofile.write((const char*)&info, sizeof(info));
ofile.close();
}
void ReadBinary(ConfigInfo& info)
{
ifstream ifile(configfile, ifstream::binary | ifstream::in);
ifile.read((char*)&info, sizeof(info));
ifile.close();
}
//文本读写
void WriteText(const ConfigInfo& info)
{
ofstream ofile(configfile);
ofile << info.port << endl;
ofile << info.ip << endl;
ofile.close();
}
void ReadText(ConfigInfo& info)
{
ifstream ifile(configfile);
ifile >> info.port;
ifile >> info.ip;
ifile.close();
}
private:
string configfile;
};
int main()
{
ConfigManager man;
ConfigInfo rinfo;
ConfigInfo winfo;
winfo.port = 80;
strcpy(winfo.ip,"127.0.0.1");
//二进制读写
man.WriteBinary(winfo);
man.ReadBinary(rinfo);
cout << rinfo.port << endl;
cout << rinfo.ip << endl;
//文本读写
man.WriteText(winfo);
man.ReadText(rinfo);
cout << rinfo.ip << endl;
cout << rinfo.port <<endl;
return 0;
}