• C++输入输出流


    C++输入输出流

    简介

    数据输入和输出过程也是数据传输的过程。数据就像流水一样从一个地方流动到另一个地方,因此,在C++中将输入输出称为“流(stream)"。

    C++的输入输出流是指由若干字节组成的字节序列,这些字节中的数据按顺序从一个对象传送到另一对象。流表示了信息从源到目的端的流动。在输入操作时,字节流从输入设备(如键盘、磁盘)流向内存,在输出操作时,字节流从内存流向输出设备(如屏幕、打印机、磁盘等)。流中的内容可以是ASCII字符、二进制形式的数据、图形图像、数字音频视频或其他形式的信息。

    实际上,在内存中为每一个数据流开辟一个内存缓冲区,用来存放流中的数据。当用cout和插入运算符“<<”向显示器输出数据时,先将这些数据送到程序中的输出缓冲区保存,直到缓冲区满了或遇到endl,就将缓冲区中的全部数据送到显示器显示出来。在输入时,从键盘输入的数据先放在键盘缓冲区中,当按回车键时,键盘缓冲区中的数据输入到程序中的输入缓冲区,形成cin流,然后用提取运算符“>>”从输入缓冲区中提取数据送给程序中的有关变量。总之,流是与内存缓冲区相对应的,或者说,缓冲区中的数据就是流。

    流类

    在C++的标准库中,将用于进行数据输入输出的类统称为”流类“。cin是流类istream的对象,cout是流类ostream的对象。要使用流类,需要在程序中包含iostream头文件。

    如上图所示,ios是抽象基类,它派生出istream和ostream。istream和ostream又共同派生出了iostream类。

    为了避免多继承的二义性,从ios派生出istream和ostream时,均使用virtual关键字(虚继承)。

    istream是用于输入的流类,cin就是该类的对象。

    ostream是用于输出的流类,cout就是该类的对象。

    ifstream是用于从文件读取数据的类。

    ofstream是用于向文件写入数据的类。

    iostream是既能用于输入,又能用于输出的类。

    fstream是既能从文件读取数据,又能向文件写入数据的类。

    流对象

    标准流对象

    iostream头文件中定义了四个标准流对象,它们是cin、cout、cerr和clog。

    cin对应于标准输入流,用于从键盘读取数据,也可以被重定向为从文件中读取数据。

    cout对应于标准输出流,用于向屏幕输出数据,也可以被重定向为向文件写入数据。

    clog对应于标准错误输出流,用于向屏幕输出错误信息,不能被重定向。

    cerr和clog的区别在于:cerr不适用缓冲区,直接向显示器输出信息;而输出到clog中的信息会先被存放到缓冲区,缓冲区满或者刷新时才输出到屏幕。

    ostream类的无参构造函数和复制构造函数都是私有的,因此在程序中一般无法定义ostream类的对象,唯一能用的ostream类的对象就是cout。

    cout可以被重定向,而cerr不能。所谓重定向,就是将输入的源或输出的目的地改变。例如,cout本来是输出到屏幕的,但是经过重定向,本该输出到屏幕上的东西就可以被输出到文件中。

    例如:

    #include <iostream>
    using namespace std;
    int main()
    {
        int x,y;
        cin >> x >> y;
        freopen("test.txt", "w", stdout);  //将标准输出重定向到 test.txt文件
        if( y == 0 )  //除数为0则输出错误信息
            cerr << "error." << endl;
        else
            cout << x /y ;
        return 0;
    }
    

    其中,freopen是个标准库函数,第二个参数w代表写模式,第三个参数代表标准输出。该语句的作用是将标准输出重定向为test.txt文件。重定向之后,所有对cout的输出都不再出现在屏幕上,而是在test.txt文件中。

    重定义流对象

    cin也可以被重定向,如果在程序中加入

    freopen("input.dat", "r", stdin);
    

    第二个参数r代表读入方式,第三个参数stdin代表输入。执行此语句后,cin就不再从键盘读入数据,而是从input.dat文件中读入数据。

    流操作算子-格式化输出

    C++中常用的输入流操纵算子如表1所示,它们都是在头文件iomanip中定义的,要使用这些流操纵算子,必须包含该头文件。

    note:"流操纵算子"一栏中的*不是算子的一部分,星号表示在没有使用任何算子的情况下,就等效于使用了该算子。例如,在默认情况下,整数是十进制形式输出的,等效于使用了dec算子。

    用法:

    #include <iomanip>
    cout << hex << 12 << "," << 24;
    
    c, 18
    
    控制符 描 述
    *dec 以十进制形式输出整数
    hex 以十六进制形式输出整数
    oct 以八进制形式输出整数
    fixed 以普通小数形式输出浮点数
    scientific 以科学计数法形式输出浮点数
    left 左对齐,即在宽度不足时将填充字符添加到右边
    *right 右对齐,即在宽度不足时将填充字符添加到左边
    setbase(b) 设置输出整数时的进制,b=8、10 或 16
    setw(w) 指定输出宽度为 w 个字符,或输人字符串时读入 w 个字符
    setfill(c) 在指定输出宽度的情况下,输出的宽度不足时用字符 c 填充(默认情况是用空格填充)
    setprecision(n) 设置输出浮点数的精度为 n。在使用非 fixed 且非 scientific 方式输出的情况下,n 即为有效数字最多的位数,如果有效数字位数超过 n,则小数部分四舍五人,或自动变为科学计 数法输出并保留一共 n 位有效数字。在使用 fixed 方式和 scientific 方式输出的情况下,n 是小数点后面应保留的位数。
    setiosflags(flag) 将某个输出格式标志置为 1
    resetiosflags(flag) 将某个输出格式标志置为 0
    boolapha 把 true 和 false 输出为字符串
    *noboolalpha 把 true 和 false 输出为 0、1
    showbase 输出表示数值的进制的前缀
    *noshowbase 不输出表示数值的进制.的前缀
    showpoint 总是输出小数点
    *noshowpoint 只有当小数部分存在时才显示小数点
    showpos 在非负数值中显示 +
    *noshowpos 在非负数值中不显示 +
    *skipws 输入时跳过空白字符
    noskipws 输入时不跳过空白字符
    uppercase 十六进制数中使用 A~E。若输出前缀,则前缀输出 0X,科学计数法中输出 E
    *nouppercase 十六进制数中使用 a~e。若输出前缀,则前缀输出 0x,科学计数法中输出 e。
    internal 数值的符号(正负号)在指定宽度内左对齐,数值右对 齐,中间由填充字符填充。

    读取一行

    cin.get

    istream& get ( char* s, streamsize n)
    istream& get ( char* s, size_t n, streamsize delim)
    

    二者的区别是前者默认以换行符结束,后者可指定结束符。n表示目标空间的大小。示例代码如下:

    #include <iostream>
    using namespace std;
    
    int main()
    {
        char a;
        char array[20]={NULL}; 
        cin.get(array,20);
        cin.get(a);
        cout<<array<<" "<<(int)a<<endl;
        return 0;
    }
    

    输入:

    123456789[回车]
    

    输出:

    123456789
    123456789 10
    

    第一排显示的是输入信息,
    第二排显示的是输出信息.

    1)从结果可以看出,cin.get(array,20);读取一行时,遇到换行符时结束读取,但是不对换行符进行处理,换行符仍然残留在输入缓冲区。第二次由cin.get()将换行符读入变量a,打印输入换行符的ASCII码值为10。这也是cin.get()读取一行与使用getline读取一行的区别所在。getline读取一行字符时,默认遇到’ ’时终止,并且将’ ’直接从输入缓冲区中删除掉,不会影响下面的输入处理。

    2)cin.get(str,size);读取一行时,只能将字符串读入C风格的字符串中,即char*,但是C++的getline函数可以将字符串读入C++风格的字符串中,即string类型。鉴于getline较cin.get()的这两种优点,建议使用getline进行行的读取。

    cin.getline

    函数作用:从标准输入设备键盘读取一串字符串,并以指定的结束符结束。

    #include <iostream>
    istream& getline(char* s, streamsize count); //默认以换行符结束
    istream& getline(char* s, streamsize count, char delim); //指定换行结束符
    
    #include <iostream>
    using namespace std;
    int main()
    {
        char array[20]={NULL};
        cin.getline(array,20); 
        cout<<array<<endl;
        return 0;
    }
    
    123456789
    123456789
    

    getline

    #include <string> 
    istream& getline ( istream& is, string& str);//默认以换行符结束
    istream& getline ( istream& is, string& str, char delim); //指定换行结束符
    
    #include <string> 
    #include <iostream>
    using namespace std;
    
    int main()
    {
        string str;
        getline(cin,str);
        cout<<str<<endl;
        system("pause");
        return 0;
    }
    
    hello world[回车]
    
    hello world
    hello world
    

    注意,getline遇到结束符时,会将结束符一并读入指定的string中,再将结束符替换为空字符。因此,进行从键盘读取一行字符时,建议使用getline,较为安全。但是,最好还是要进行标准输入的安全检查,提高程序容错能力。

    cin.getline()类似,但是cin.getline()属于istream流,而getline()属于string流,是不一样的两个函数。

    gets

    char *gets( char *buffer );
    
    #include <iostream>
    using namespace std;
    int main()
    {
        char array[20]={NULL};
        gets(array);
        cout<<array<<endl;
        system("pause");
        return 0;
    }
    

    但是c++中找不到gets函数...

    123
    123
    

    文件流

    头文件

    由于文件设备并不像显示器屏幕与键盘那样是标准默认设备,不能像cout那样预先定义的全局对象,所以我们必须自己定义一个该类的对象。

    • ifstream类,它是从istream类派生的,用来支持从磁盘文件的输入。
    • ofstream类,它是从ostream类派生的,用来支持向磁盘文件的输出。
    • fstream类,它是从iostream类派生的,用来支持对磁盘文件的输入输出。

    文件原理

    文件打开:文件打开都有一个文件指针,该指针的初始位置由I/O方式指定,每次读写都从文件指针的当前位置开始。每读入一个字节,指针就后移一个字节。当文件指针移到最后,就会遇到文件结束EOF(文件结束符也占一个字节,其值为-1),此时流对象的成员函数eof的值为非0值(一般设为1),表示文件结束了。
    文件关闭:实际上是解除该磁盘文件与文件流的关联,原来设置的工作方式也失效,这样,就不能再通过文件流对该文件进行输入或输出
    文件类型:
    1、ASCII文件:文件的每一个字节中均以ASCII代码形式存放数据,即一个字节存放一个字符,这个文件就是ASCII文件(或称字符文件)。
    2、二进制文件:文件中的信息不是字符数据,而是字节中的二进制形式的信息,因此它又称为字节文件.

    打开文件

    函数原型:

    void open(const char *filename, ios::openmode mode);
    

    open() 成员函数的第一参数指定要打开的文件的名称和位置,第二个参数定义文件被打开的模式。

    模式标志 描述
    ios::app 追加模式。所有写入都追加到文件末尾。
    ios::ate 文件打开后定位到文件末尾。
    ios::in 打开文件用于读取。
    ios::out 打开文件用于写入。
    ios::trunc 如果该文件已经存在,其内容将在打开文件之前被截断,即把文件长度设为 0。

    以写入模式打开文件,并希望截断文件,以防文件已存在:

    ofstream outfile;
    outfile.open("file.dat", ios::out | ios::trunc );
    

    以读写方式打开文件:

    ifstream  afile;
    afile.open("file.dat", ios::out | ios::in );
    

    关闭文件

    当 C++ 程序终止时,它会自动关闭刷新所有流,释放所有分配的内存,并关闭所有打开的文件。但程序员应该养成一个好习惯,在程序终止前关闭所有打开的文件。
    下面是 close() 函数的标准语法,close() 函数是 fstream、ifstream 和 ofstream 对象的一个成员。

    void close();
    

    写入文件-输出

    在 C++ 编程中,我们使用流插入运算符( << )向文件写入信息,就像使用该运算符输出信息到屏幕上一样。唯一不同的是,在这里您使用的是 ofstream 或 fstream 对象,而不是 cout 对象。

    读取文件-输入

    在 C++ 编程中,我们使用流提取运算符( >> )从文件读取信息,就像使用该运算符从键盘输入信息一样。唯一不同的是,在这里您使用的是 ifstream 或 fstream 对象,而不是 cin 对象。

    写入实例

    下面的 C++ 程序以读写模式打开一个文件。在向文件 afile.dat 写入用户输入的信息之后,程序从文件读取信息,并将其输出到屏幕上:

    #include <fstream>
    #include <iostream>
    using namespace std;
     
    int main ()
    {
        
       char data[100];
     
       // 以写模式打开文件
       ofstream outfile;
       outfile.open("afile.dat");
     
       cout << "Writing to the file" << endl;
       cout << "Enter your name: "; 
       cin.getline(data, 100);
     
       // 向文件写入用户输入的数据
       outfile << data << endl;
     
       cout << "Enter your age: "; 
       cin >> data;
       cin.ignore();
       
       // 再次向文件写入用户输入的数据
       outfile << data << endl;
     
       // 关闭打开的文件
       outfile.close();
     
       // 以读模式打开文件
       ifstream infile; 
       infile.open("afile.dat"); 
     
       cout << "Reading from the file" << endl; 
       infile >> data; 
     
       // 在屏幕上写入数据
       cout << data << endl;
       
       // 再次从文件读取数据,并显示它
       infile >> data; 
       cout << data << endl; 
     
       // 关闭打开的文件
       infile.close();
     
       return 0;
    }
    
    Writing to the file
    Enter your name: Zara
    Enter your age: 9
    Reading from the file
    Zara
    9
    

    上面的实例中使用了 cin 对象的附加函数,比如 getline()函数从外部读取一行,ignore() 函数会忽略掉之前读语句留下的多余字符。

    文件位置指针

    istream 和 ostream 都提供了用于重新定位文件位置指针的成员函数。这些成员函数包括关于 istream 的 seekg("seek get")和关于 ostream 的 seekp("seek put")。

    seekg 和 seekp 的参数通常是一个长整型。第二个参数可以用于指定查找方向。查找方向可以是 ios::beg(默认的,从流的开头开始定位),也可以是 ios::cur(从流的当前位置开始定位),也可以是 ios::end(从流的末尾开始定位)。

    文件位置指针是一个整数值,指定了从文件的起始位置到指针所在位置的字节数。下面是关于定位 "get" 文件位置指针的实例:

    // 定位到 fileObject 的第 n 个字节(假设是 ios::beg)
    fileObject.seekg( n );
     
    // 把文件的读指针从 fileObject 当前位置向后移 n 个字节
    fileObject.seekg( n, ios::cur );
     
    // 把文件的读指针从 fileObject 末尾往回移 n 个字节
    fileObject.seekg( n, ios::end );
     
    // 定位到 fileObject 的末尾
    fileObject.seekg( 0, ios::end );
    

    参考链接:
    https://blog.csdn.net/qq_41631051/article/details/91448649
    https://blog.csdn.net/weixin_34194379/article/details/92288825?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase
    https://www.runoob.com/cplusplus/cpp-files-streams.html

  • 相关阅读:
    Android下加载GIF图片
    拍照、相册及裁剪的终极实现(一)——拍照及裁剪功能实现
    阿里巴巴矢量库
    ActiveAndroid 管理数据库
    利用box-shadow制作loading图
    适用于移动端的地址选择器
    常用的不易记忆的css自定义代码
    关于js中一个对象当做参数传递是按值传递还是按引用传递的个人看法
    JavaScript之函数柯里化
    CSS3实现图片渐入效果
  • 原文地址:https://www.cnblogs.com/chendeqiang/p/12861572.html
Copyright © 2020-2023  润新知