面向对象程序设计-文件读写

面向对象程序设计-文件读写

本文字数:1521  阅读时长:4分钟

访问量 0

  • 标准输出流分成3个流对象:
    • cout流:正常的输出信息,用于交互的控制台信息。缓冲区满/回车输出
    • cerr流:向标准出错设备输出。立即输出,不等
    • clog流:向标准出错设备输出。缓冲区满/回车输出
      3者都是默认向显示器输出。
  • 流成员函数put():与putchar()功能相同,输出一个字符。返回值是流对象,这使得你得以连续调用put:cout.put('a').put('b);
  • 文件结束符:ctrl+D
  • 文件结束标记:EOF
  • 文件读写头文件#include <fstream>
  • 文件读写流类:ifstream(输入),ofstream(输出),fstream(i+o),可以用这3种类建立流对象,进行文件读写操作。

打开文件

指定某个流对象操作的文件。

cpp
流对象.open(文件名, 打开方式);

打开方式

fab116ba5e87d93b9983330de780aa76.jpg

  • no开头的2个,gcc中不存在,MSVC下是ios::_Nocreate和ios::_Noreplace.
  • 打开方式要和选择的流类匹配兼容。如果矛盾的话,你填的这个打开方式会被自动忽略成空气。

文件名

  • 工作目录一般是可执行文件所在目录,这是最多的情况。特例就是,如果是Visual Studio里运行,那vs会进行一个强制设定,把工作目录设到源文件所在目录。
  • 文件名这里可以填相对路径也可以绝对路径。Windows的根目录是每个盘符下的根目录,默认是同一个盘符。所以Windows可以在根目录的在外面指定盘符,比如c:。所有情况下都支持正斜杠的路径,包括Windows也支持。Windows额外支持反斜杠的路径,因为Windows是这样的,Linux不支持反斜杠。如果你要在Windows用反斜杠,需要注意这个反斜杠需要转义。一般用正斜杠最通用最省事,直接统一。

文件打开状态

并不一定是都能打开成功的。用is_open()方法来看这个open有没有成功,返回值1/0

ios:out

  1. 文件不存在:自动创建文件,打开成功
  2. 文件存在并可以读写:自动清空已经存在的文件(小心!!!),打开成功
  3. 文件存在并只读:打开失败

ios::out | ios::_Nocreate

  1. 文件不存在:打开失败
  2. 文件存在并可以读写:自动清空已经存在的文件(小心!!!),打开成功
  3. 文件存在并只读:打开失败

ios::in

  1. 文件不存在:打开失败
  2. 文件存在:打开成功(只读无所谓,in就是读)

文本读写操作

  • ios::app是追加,这样打开的时候就不会清空存在的文件了。
  • EOF
cpp
while(!in.eof()){
	ch = in.get();
	putchar(ch);
}

这是一个错误的写法,因为这个会把EOF给读到并且输出。EOF不是文件内容中真实存在的标记,是给程序知道文件读完了。下面是正确的做法

cpp
while((ch=in.get())!=EOF){
	cout.put(ch);
}

因为输入流是遇到换行才输进来,所以如果文件的最后没有换行,程序没等到换行,先遇到了EOF,这时候内容才输进来。这种情况的话,这一段东西是正常输入了,没有问题,所以fail()是0;但是现在读过EOF了,输入状态已经坏掉了,下次再输入会出问题,good()是0.

所以对于fail和good之争,大概的解释是:good用于反映输入流的好坏情况,现在能不能继续进行输入,侧重于下一次的好坏;fail用于本次读取的字符流有没有问题,这些内容是否可信,侧重于本次读入内容。两者不是互斥,因为像文件结尾不换行,就是会同时让输入内容没问题,但是输入状态坏掉。如果是要判断内容输入是否正常,那就是用fail,这也是高程那里用fail的原因。

二进制字节读写操作

  • ios::binary把文件以二进制的方式打开进行读写。
  • 以字节为单位进行读写,用read/write进行读写。
cpp
// 把从当前文件指针开始的长度个字节,写入到对应内存空间
read(内存空间首指针, 长度)
// 把从指针开始长度个字节的数据,从内存写入当前文件指针的位置。
write(内存空间首指针, 长度)

内存指针必须转成char基类型,因为是一个字节大小。