C++的IO流

版权声明:本文为博主原创文章,欢迎转载,转载请声明出处! https://blog.csdn.net/hansionz/article/details/85250142

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语言的流是基于缓冲区实现的,输入输出的区别在于方向不同和对数据的操作不同。

流可以分为两种:

  • 文本流:在缓冲区中读出和写入时是基于ASCIIUnicode字符编码的。写入缓冲区的最大长度规定为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的流对象默认是outifstream默认是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);

二进制读写时,我们采用writeread成员函数进行操作。

  • 其他的成员函数入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;
}

猜你喜欢

转载自blog.csdn.net/hansionz/article/details/85250142