输入输出流[标准输入输出,文件输入输出,字符输入输出(get(),getline())]

  • 标准I/O

    • 对系统指定的标准设备的输入和输出。即从键盘输入数据,输出到显示器屏幕。
  • 文件I/O

    • 外存磁盘文件为对象进行输入和输出,即从磁盘文件输入数据,数据输出到磁盘文件。
  • I/O

    • 内存中指定的空间进行输入和输出。通常指定一个字符数组作为存储空间(实际上可以利用该空间存储任何信息)。
  • C++I/O操作是类型安全(type safe)的

    • 编译系统对数据类型进行严格的检查,凡是类型不正确的数据都不可能通过编译。
  • C++I/O操作是可扩展的

    • 不仅可以用来输入输出标准类型的数据,也可以用于用户自定义类型的数据。
  • C++的输入输出流是指由若干字节组成的字节序列,这些字节中的数据按顺序从一个对象传送到另一对象。流表示了信息从源到目的端的流动。

  • 在内存中为每一个数据流开辟一个内存缓冲区,用来存放流中的数据。流是与内存缓冲区相对应的,或者说,缓冲区中的数据就是流。

  • C++I/O库中的类称为流类(stream class)。用流类定义的对象称为流对象。

    • coutcin并不是C++语言中提供的语句,它们是iostream类的对象,

在这里插入图片描述在这里插入图片描述

  • 头文件(include)是程序与类库的接口,iostream类库的接口分别由不同的头文件来实现。常用的有

    • iostream包含了对输入输出流进行操作所需的基本信息。
    • fstream用于用户管理的文件的I/O操作。
    • strstream用于字符串流I/O
    • stdiostream用于混合使用CC++I/O机制时。
    • iomanip在使用格式化I/O时应包含此头文件。
  • iostream头文件中

    • 定义的ios,istream,ostream,iostream,istream _withassign, ostream_withassign,iostream_withassign等。
    • 定义了4种流对象
      • cinistream的派生类istream_withassign的对象,它是从标准输入设备(键盘)输入到内存的数据流,称为cin流或标准输入流。
      • coutostream的派生类ostream_withassign的对象。
        • cout流在内存中对应开辟了一个缓冲区,用来存放流中的数据,当向cout流插入一个endl时,不论缓冲区是否已满,都立即输出流中所有数据,然后插入一个换行符,并刷新流(清空缓冲区)。
        • 流通常是传送到显示器输出,也可以被重定向输出到磁盘文件
      • cerr:向输出设备(显示器) 输出出错信息
        • 只能在显示器输出。cerr流中的信息是用户根据需要指定的。
        • 不经过缓冲区,直接向显示器上输出有关信息,
      • clog (console log):向输出设备(显示器) 输出出错信息
        • clog中的信息存放在缓冲区中,缓冲区满后或遇endl时向显示器输出。

关于格式输出点这里

  • 用流成员函数put输出字符

    • ostream类除了提供上面介绍过的用于格式控制的成员函数外,还提供了专用于输出单个字符的成员函数put。如cout.put(′a′);调用该函数的结果是在屏幕上显示一个字符a
    • 也可以改用putchar函数实现。这个是在C语言中提供的。
  • cin流

    • cinistream类的对象,它从标准输入设备(键盘)获取数据,程序中的变量通过流提取符“>>”从流中提取数据。
    • 流提取符“>>”从流中提取数据时通常**跳过输入流中的空格、tab键、换行符等空白字符。 **
    • 注意: 只有在输入完数据再按回车键后,该行数据才被送入键盘缓冲区,形成输入流,提取运算符“>>”才能从中提取数据。
  • 用于字符输入的流成员函数

    1. get函数读入一个字符 :无参数的,有一个参数的,有3个参数的。
      1. 不带参数的get函数:cin.get()
        用来从指定的输入流中提取一个字符,函数的返回值就是读入的字符。若遇到输入流中的文件结束符,则函数值返回文件结束标志EOF(End Of File) 。
      #include <iostream>
      int main( )
      {int c;
       cout<<″enter a sentence:<<endl;
       while((c=cin.get())!=EOF)
        cout.put(c);
       return 0;
      }
      运行情况如下: 
      enter a sentence:
      I study C++ very hard.(输入一行字符)
      I study C++ very hard.              (输出该行字符)
      ^Z↙(程序结束)
      1. 有一个参数的get函数:cin.get(ch)
        从输入流中读取一个字符,赋给字符变量ch。如果读取成功则函数返回非0值(真),如失败(遇文件结束符) 则函数返回0值(假)。
      while(cin.get(c))  //读取一个字符赋给字符变量c,如果读取成功,cin.get(c)为真
      {cout.put(c);}
      1. 有3个参数的get函数:cin.get(字符指针/字符数组,字符个数n,终止字符)
        从输入流中读取n-1个字符,赋给指定的字符数组(或字符指针指向的数组),如果在读取n-1个字符之前遇到指定的终止字符,则提前结束读取。如果读取成功则函数返回非0值(真),如失败(遇文件结束符) 则函数返回0值(假)。
      cin.get(ch,10,′\n′);  
      <===>cin.get(ch,10);//默认换行符为终止字符,终止字符也可以用其他字符,如'x'
      cin.get(ch,10);
      char ch[20];
    2. 成员函数getline函数读入一行字符:cin.getline(字符数组(或字符指针),字符个数n,终止标志字符);
  • cin.get(...)cin.getline(...)的区别(这段话来自北大李戈老师的ppt)
    北大 李戈老师ppt
    在这里插入图片描述
    在这里插入图片描述

  • istream类的其他成员函数

    • eof 函数(end of file)的缩写,表示“文件结束”。while(!cin.eof()){}
      • 从输入流读取数据,如果到达文件末尾(遇文件结束符),eof函数值为非零值(表示真),否则为0(假)。
    • peek函数:观测下一个字符。c=cin.peek( );
      • 函数的返回值是指针指向的当前字符,但它只是观测,指针仍停留在当前位置,并不后移。如果要访问的字符是文件结束符,则函数值是EOF(-1)。而get则要读取并且移动指针。
    • putback函数cin.putback(ch);
      • 将前面用getgetline函数从输入流中读取的字符ch返回到输入流,插入到当前指针位置,以供后面读取。
    • ignore函数cin,ignore(n, 终止字符)
      • 跳过输入流中n个字符,或在遇到指定的终止字符时提前结束(此时跳过包括终止字符在内的若干字符)。如:ignore(5, ′A′);//跳过输入流中5个字符,遇′A′后就不再跳了
      • 也可以不带参数或只带一个参数。如ignore( )(n默认值为1,终止字符默认为EOF)。相当于ignore(1,EOF)
      • 看到前面有讲,如果用cin.get(),则缓冲区的指针是停留在终止字符那里的。这样会导致如果第二次cin.get()的终止符和上一次的一样,那么就不能继续前进。想要避免这种情况可以用ignore
int main( )
{
char ch[20];
 cin.get(ch,20,/);
 cout<<ch<<endl;
 cin.ignore( );//跳过输入流中一个字符
 cin.get(ch,20,/);
 cout<<ch<<endl;
 return 0;
}
/* I like C++./I study C++./I am happy.↙ I like C++. I study C++.//没有ignore的话,这里的cin.get()就无法输入有效字符。 */

peak and putback实例(下图)
在这里插入图片描述



  • 文件操作与文件流

    • 所谓“文件”,一般指存储在外部介质上数据的集合。
    • 一批数据是以文件的形式存放在外部介质上的。
    • 操作系统是以文件为单位对数据进行管理的。
    • 要向外部介质上存储数据也必须先建立一个文件(以文件名标识),才能向它输出数据。
  • 外存文件

    • 磁盘文件(使用最广泛)
    • 光盘文件
    • U盘文件
  • 对用户来说,常用到的文件有两大类

    • 程序文件(program file)
    • 数据文件(data file)。程序中的输入和输出的对象就是数据文件。根据文件中数据的组织形式,可分为:
      • ASCII文件
      • 二进制文件

对于字符信息,在内存中是以ASCII代码形式存放的,因此,无论用ASCII文件输出还是用二进制文件输出,其数据形式是一样的。但是对于数值数据,二者是不同的。例如有一个长整数100000,在内存中占4个字节,如果按内部格式直接输出,在磁盘文件中占4个字节,如果将它转换为ASCII码形式输出,则要占6个字节。
在这里插入图片描述

  • 高级的I/O

    • 若干个字节组合为一个有意义的单位,然后以ASCII字符形式输入和输出。传输大容量的文件时由于数据格式转换,速度较慢,效率不高。
  • 低级的I/O

    • 字节为单位输入和输出的,在输入和输出时不进行数据格式的转换。这种输入输出速度快、效率高,一般大容量的文件传输用无格式转换的I/O。但使用时会感到不大方便。
  • 文件流(本身不是文件,而只是以文件为输入输出对象的流)

    • 外存文件为输入输出对象的数据流。
    • 输出文件流是从内存流向外存文件的数据
    • 输入文件流是从外存文件流向内存的数据。
    • 每一个文件流都有一个内存缓冲区与之对应。
  • 对磁盘文件的操作是通过文件流对象(而不是cincout)实现的。文件流对象是用文件流类定义的,而不是用istreamostream类来定义的。

    • ifstream类,它是从istream类派生的。 用来支持从磁盘文件的输入
    • ofstream类,它是从ostream类派生的。 用来支持向磁盘文件的输出
    • fstream类,它是从iostream类派生的。 用来支持对磁盘文件的输入输出。
  • 建立一个输出文件流对象: ofstream outfile;

  • 打开磁盘文件

    • 为文件流对象和指定的磁盘文件建立关联,以便使文件流流向指定的磁盘文件。
    • 指定文件的工作方式。
      • 调用文件流的成员函数open。如文件流对象.open(磁盘文件名,输入输出方式);
      • 定义文件流对象时指定参数。如:ostream outfile(″f1.dat″,ios::out);
    • 每一个打开的文件都有一个文件指针。
    • 可以用“位或”运算符“|”对输入输出方式进行组合。
    • 如果打开操作失败,open函数的返回值为0(假),如果是用调用构造函数的方式打开文件的,则流对象的值为0
  • 关闭磁盘文件outfile.close( ); //将输出文件流所关联的磁盘文件关闭

  • ASCII文件:文件的每一个字节中均以ASCII代码形式存放数据,即一个字节存放一个字符。

    • 用流插入运算符“<<”和流提取运算符“>>”输入输出标准类型的数据。
    • 用文件流的put,get,geiline等成员函数进行字符的输入输出
  • 二进制文件

    • 将内存中数据存储形式不加转换地传送到磁盘文件,因此它又称为内存数据的映像文件
    • 因为文件中的信息不是字符数据,而是字节中的二进制形式的信息,因此它又称为字节文件。
    • 二进制文件除了可以作为输入文件或输出文件外,还可以是既能输入又能输出的文件。这是和ASCII文件不同的地方。
    • istream类的成员函数readwrite读写二进制文件
      • istream& read(char *buffer,int len);
      • ostream& write(const char * buffer,int len);
    • 字符指针buffer指向内存中一段存储空间。len是读写的字节数。调用的方式为
      • outfile. write(p1,50);
      • infile.read(p2,30);
  • 在磁盘文件中有一个文件指针,用来指明当前应进行读写的位置。对于二进制文件,允许对指针进行控制,使它按用户的意图移动到所需的位置,以便在该位置上进行读写。文件流提供一些有关文件指针的成员函数。如指针的定位:infile.seekg(-50,ios::cur);//输入文件中的指针从当前位置后移50字节

  • 随机访问二进制数据文件

  • 字符串流(内存流)。字符串流类有``istrstream,ostrstream 和 strstream`

    • **内存中用户定义的字符数组(字符串)**为输入输出的对象,即将数据输出到内存中的字符数组,或者从字符数组(字符串)将数据读入。
    • 字符串流也有相应的缓冲区,开始时流缓冲区是空的。如果向字符数组存入数据,随着向流插入数据,流缓冲区中的数据不断增加,待缓冲区满了(或遇换行符),一起存入字符数组。如果是从字符数组读数据,先将字符数组中的数据送到流缓冲区,然后从缓冲区中提取数据赋给有关变量。
    • 在字符数组中可以存放字符,也可以存放整数、浮点数以及其他类型的数据。在向字符数组存入数据之前,要先将数据从二进制形式转换为ASCII代码(读出时则相反转换),然后存放在缓冲区,再从缓冲区送到字符数组。
    • 流缓冲区中的数据格式与字符数组相同。
  • 字符流与文件流的区别

    • 输出时数据不是流向外存文件,而是流向内存中的一个存储空间。输入时从内存中的存储空间读取数据。
    • 字符串流对象关联的不是文件,而是内存中的一个字符数组,因此不需要打开和关闭文件。
    • 每个文件的最后都有一个文件结束符,表示文件的结束。而字符串流所关联的字符数组中没有相应的结束标志,用户要指定一个特殊字符作为结束符,在向字符数组写入全部数据后要写入此字符。
  • 字符串流类没有open成员函数,因此要在建立字符串流对象时通过给定参数来确立字符串流与字符数组的关联。即通过调用构造函数来解决此问题。

    • 建立输出字符串流对象ostrstream strout(ch1,20);。建立输出字符串流对象strout,并使strout与字符数组ch1关联(通过字符串流将数据输出到字符数组ch1),流缓冲区大小为20。
      • 构造函数原型ostrstream::ostrstream(char *buffer,int n,int mode=ios::out);。buffer是指向字符数组首元素的指针,n为指定的流缓冲区的大小(一般选与字符数组的大小相同,也可以不同),第3个参数是可选的,默认为ios::out方式。
    • 建立输入字符串流对象istrstream strin(ch2,20);
      • 构造函数原型istrstream::istrstream(char *buffer);或者 istrstream::istrstream(char *buffer,int n) 。buffer是指向字符数组首元素的指针,用它来初始化流对象,n是缓冲区大小。
    • 建立输入输出字符串流对象strstream strio(ch3,sizeof(ch3),ios::in|ios::out);
      • 构造函数原型strstream::strstream(char *buffer,int n,int mode);