【C++】文件IO流
一起来康康C++中的文件IO操作吧
[TOC]
1.operator bool
之前写OJ的时候,就已经用过上面这种方式来获取多组测试用例
1 | string s; |
不过之前一直没有去了解这里的底层原理是什么,借此机会一并说明
io流可以进行while判断的依据,是因为库的源码中重载了operator bool
没错,operator
不仅可以重载一个操作符,它还可以重载一个类型!即将这个类转换为bool类型,return
一个bool类型的值用于while的判断
同理,重载int/double
这些类型都是可行的!
另外,要想停止上面的多组输入,在VS下可以用
ctrl+z
的方式解决,而不要用ctrl+c
直接杀掉进程
2.C++文件IO流
C++的文件io类设计的较为复杂,其中还出现了菱形继承,也就是我们最常用的iostream
上面提到的operator bool
就是基类IOS
实现的,子类都没有去重写
- cout为标准输出,将数据从内存流中输入到显示器上
- cin为标准输入,通过键盘输入数据到程序中
- cerr用于标准错误的输出
- clog进行日志输出
其中需要注意的一点是,空格和回车会被当作数据之间的分隔符,所以字符串中不能有空格,回车和空格也不能通过cin读入
如果需要读入带空格的完整一行,可以使用getline
函数
- 为什么cin和cout可以输入输出所有类型?
因为库里面已经将所有类型通过操作符重载<<
和>>
实现了,达到了自动类型识别的效果
3.文件操作
C++标准库中提供的打开方式如下,我们可以根据不同情况传入不同的值,或者一次性用按位或|
传入多个打开方法
同时因为C++类和对象会自动调用析构函数,所以我们也不需要手动close文件
3.0 关于按位与的说明
这里为何可以用按位与传入多个方法?
假设这些方法就是简单的数字2/4/8
(必须是2的倍数)我们可以通过按位与了之后,在按位或,判断某一个数字是否在其中
如果或了之后的数字等于它本身,说明数据在其中!
- 为什么需要是2的倍数呢?
这种方法在linux中常见,比如linux系统的文件接口
3.1 ifstream
这个对象是用于读取文件的,默认情况下,传入的打开方法为in
1 | void test1() |
因为重载了bool,所以可以很方便的直接用while来判断结束,成功输出了文件中的内容
1 | ifstream ifs("test.txt"); |
第二种读取方法采用了流插入>>
上面提到过,流提取和插入的时候,会把空格和换行当作数据的分隔符,所以它是不能打印出空格和换行
3.2 ofstream
写文件的方式同上,用out方法打开文件就可以了(默认传的就是out)
1 | ofstream ifs2("test1.txt",ios::out); |
不过这个和C语言的w方法一样,写入的时候会覆盖文件中已有的内容。如果想进行追加,则需要在后面加上app
;如果是执行二进制读写,则需要与上ios::binary
1 | ofstream ifs2("test1.txt",ios::out|ios::app); |
运行成功后会在文件尾部追加内容
注意,这里的字符串不能用string进行处理,因为string内部只存了一个指向字符串空间的指针,写入string相当于把指针写入进文件中,是么有用的!
流插入文本
但是,如果我们用<<
进行提取的时候,就可以用string了
1 | void test2() |
程序运行后,会把test.txt
中的内容输出到控制台,同时写入到test1.txt
最后还会写入一个string
的内容
这是因为我们调用<<
的时候,就和cin<<s
一样,调用的是string
重载的流提取操作符
底层实现的时候会将其转为C语言的字符串,从而写入到了文件中
所以当我们需要写入一个自定义类型的时候,可以重载流提取操作符,不仅可以更方便的打印,还可以写入到文件中
3.3 ostringstream/istringstream
这个类可以将不同的类型转为字符串
这种操作被称为序列化和反序列化,在处理自定义类型的时候非常好用
1 | struct Date |
3.4 stringstream
这个对象可以用于字符串拼接,也可以用来将其他类型转为str
1 | stringstream sstream; |
3.5使用stringstream的注意事项
stringstream实现转换,实际上是维护了一个string对象实现的
我们可以使用
str("")
清空里面的string对象,设置为空字符串多次数据类型转换的时候,需要用
clear()
来清空,才能正确转换。不过clear()
不会清空底层的string对象因为使用的是string对象,所以使用的时候不需要格式化控制,可以自动推导类型
stringstreams
在转换结尾时(即最后一个转换后),会将其内部状态设置为badbit
因此下一次转换是必须调用clear()
将状态重置为goodbit
才可以继续转换
这里在第一次调用stringstream
操作后,我们没有进行clear,会发现后续的double类型转换失败了
执行了clear之后,转换成功!
结语
关于C++IO流操作的基本认识到这里就over了。
因为在实际中用的并不算多,所以这部分的内容大多数是了解一二,知道如何使用,以及3.0
中提到的按位与操作是怎么实现的就OK了!