• c++输入输出文件操作stream


    系列文章目录

    C++ IO库



    前言


    一、文件IO

    概述

    c++程序把输入和输出看作字节流。输入时,程序从输入流中抽取字节:输出时,程序将字节流插入到输出流中。

    在这里插入图片描述
    一般输入和输出都有缓冲区。

    C++程序通常在用户按下回车键时刷新输入缓冲区。

    cin: 标准输入流
    cout: 标准输出流
    如果输出被重定向到文件,则标准错误流依然会被输出到屏幕
    cerr: 标准错误流,无缓冲区
    clog: 标准错误流,有缓冲区

    cout

    ostream类将输出转化为字符字节流

    put() 显示字符
     cout.put(‘W’).put(65.1);
    write() 显示字符串
     cout.write(“abcd”, 2).write(“ab”, 9);
     long val = 234234; cout.write((char*)&val, sizeof(long));
     将val内存中的数据作为字节字符输出到屏幕

    输出缓冲区
    输出缓冲区为512字节或为其整数倍
    当输出为磁盘时有缓冲区,当输出为屏幕时会进行优化,也可显示指出刷新输出缓冲区:
    cout << flush (刷新输出换出区) << endl(刷新输出换出区并插入换行符); flush(cout)也可

    格式化
    ostream插入运算符将输入转换成文本输出。

    1. 数字显示方式:dec, hex, oct
    2. 调整字段宽度:cout.width(x)
    3. 填充字符:cout.fill(‘*’)
    4. 设置浮点数的显示精度:cout.precision(2)
    5. 打印末尾的0和小数点
    6. cout.setf(ios_base::uppercase)
      常量含义
      ios_base::boolalpha输入和输出bool值,可以为true或false
      ios_base::showbase对于输出,使用C++基数前缀(0, 0x)
      ios_base::showpoint显示末尾的小数点
      ios_base::uppercase对于16进制输出,使用大写字母,E表示法
      ios_base::showpos在正数前加+
    7. 标准控制符:略
    8. 头文件iomanip

    cin

    cin 对象将标准输入表示为字节流。

    对于如下代码:
     int ele;
     cin >> ele;
    假设键入下面的字符:
     -123Z
      运算符将读取字符-123,因为它们都是整数的有效部分。但Z字符不是有效字符,因此输入中最后一个可接受的字符是3。Z将留在输入流中,下一个cin语句将从这里开始读取。与此同时,运算符将字符序列-123转换为一个整数值,并将它付给ele。
      输入有时可能没有满足程序的期望。例如,假设输入的是Zcar,而不是-123Z。在这种情况下,抽取运算符将不会修改ele的值,并返回0(如果istream对象的错误状态被设置,if或while语句将判定该对象为false)。返回值false让程序能够检查输入是否满足要求。

    while(cin >> num);
    
    • 1

    由于输入被缓冲。因此通过键盘输入的第二行在用户按下enter之前,不会被发送给程序。然而,循环在字符Z处停止了对输入的处理,因此它不与任何一种浮点格式匹配。输入与预期格式不匹配反过来将当导致表达式cin>>input的结果为false,因此while循环被终止。

    成员描述
    eofbit如果到达文件尾,则设置为1
    badbit如果流被破坏,则设置为1:例如,文件读取错误
    failbit如果输入操作未能读取预期的字符或输出操作没有写入预期的字符,则设置为1
    goodbit另一种表示0的方法
    good()如果流可以使用(所有的位都被清除),则返回true
    eof()如果eofbit被设置,则返回true
    bad()如果badbit被设置,则返回true
    fail()如果badbit或failbit被设置,则返回true
    rdstate()返回流状态
    exceptions()返回一个位掩码,指出那些标记导致异常被引发
    exceptions(isostate ex)设置那些状态将导致clear()引发异常:例如,如果ex是eofbit,则如果eofbit被设置,clear()将引发异常
    clear(iostate s)将流状态设置为s:s的默认值为0(goodbit):如果(restate()& exceptions())!=0, 则引发异常 basic_ios::failure
    setstate(iostate s)调用clear(rdstate() | s)。这将设置与s中设置的为对应的流状态为,其他流状态为保持不变

    其他istream类方法

    int ct = 0;
    char ch;
    do{
      cin.get(ch);
      cout << ch;
      ct++;
    }while(ch != '\n\);
    cout << ct << endl;
    // 若为下面的则跳过空格
    int ct = 0;
    char ch;
    do{
      cin >> ch;
      cout << ch;
      ct++;
    }while(ch != '\n\);
    cout << ct << endl;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    文件输入和输出

    #include 
    
    ofstream fout("file.name"); // or f.open("xxx");
    ifstream fin("file.name");
    
    char ch;
    while(fin.get(ch)); // 一次读取一个字符,直到文件结尾,EOF
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    以默认模式打开文件进行输出将自动把文件的长度阶短为零,这相当于删除已有的内容

    流状态

    if(fin);  // 打开成功为1,失败为0
    if(fin.is_open());  // 可检查“文件模式”是否正确
    
    // 一次打开多个文件
    ifstream fin;
    fin.open("xxx1");
    ...
    fin.close();
    fin.clear();
    fin.open("xxx2");
    ...
    fin.close();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    文件模式

    常量含义
    io_base::in打开文件,以便读取
    io_base::out打开文件,以便写入
    io_base::ate打开文件,并移到文件尾
    ios_base::app追加到文件尾
    ios_base::trunc如果文件存在,则截短文件
    ios_base::binary二进制文件
    ofstream.open("xxx", ios_base::out | ios_base::trunc);
    ofstream.open("xxx", ios_base::out | ios_base::app);
    
    • 1
    • 2
    1. 文本格式
    2. 二进制文件

    以二进制形式写读文件

    ofstream fout("planets.dat", ios_base::out | ios_base::app | ios_base::binary);
    fout.write( (char*)&pl, sizeof(pl));
    
    ifstream fin("planets.dat", ios_base::in | ios_base::binary);
    fin.read((char*)&pl, sizeof(pl);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    随机存取: 直接移动(不是依次移动)到文件的任何位置。随机存取常被用于数据库文件,程序维护一个独立的索引文件,该文件指出数据在主数据文件中的位置。

    fstream类从iostream类派生,后者基于istream和ostream连个类,因此它继承了它们的方法。它还继承了两个缓冲区,一个用于输入,一个用于输出,并能同步化这两个缓冲区的处理。也就是说当程序读写文件时,它将协调地移动输入缓冲区中的输入指针和输出缓冲区中的输出指针。
    读写模式:
    finout.open(file, ios_base::in | ios_base::out | ios_base::binary);
    seekp ofstream
    seekg ifstream
    seekp()用于将输出指针移到指定的文件位置。seekg(),原型:
    basic_istream& seekg(off_type, ios_base::seekdir);
    basic_istream& seekg(pos_type);
    equal to:
    istream& seekg(streamoff, ios_base::seekdir);
    istream& seekg(streampos);
      第一个原型定位到离第二个参数指定的文件位置特定距离的位置,第二个原型定位到离文件开头特定距离的位置。
    assume fin is a ifstream object:

    fin.seekg(30, ios_base::beg);  // 30 bytes beyond the beginning
    fin.seekg(-1, ios_base::cur);   // back up one byte
    fin.seekg(0, ios_base::end);   // go to the end of the file
    
    • 1
    • 2
    • 3

    将streampos位置看作相对文件开始处的位置(第一个字节编号为0),偏移量
    fin.seekg(112);

      如果要检查文件指针的当前位置,则对于输入流,可以使用tellg()方法,对于输出流,可以使用tellp()方法,它们返回streampos。fstream对象的输入输出指针同步。如果使用istream ostream对象则输入输出指针不同步。

    打开文件、移到文件开头并显示文件内容:

    fstream finout;  // read and write streams
    finout.open(file, ios::in | ios::out | ios::binary);
    // note: some unix systems require omitting | ios::binary
    int ct = 0;
    if (finout.is_open()) {
      finout.seekg(0);  // go to beginning
      cout << "Here" << file << "file:\n";
      while(finout.read((char*)&pl, sizeof(pl)){
        cout << ct++ << ": " << setw(LIM) << pl.name << ": "
        << setprecision(0) << setw(12) << pl.population
        << setprecision(2) << setw(6)  << pl.g << endl;
      }
      if (finout.eof()) {  // 读取到文件尾
        finout.clear();    // clear eof flag
      } else {             // 没有读到文件尾,而是其他故障导致
        cerr << "Error in reading" << file << ".\n";
        exit(EXIT_FAILURE);
      }
    } else {  // 若文件打开失败
      cerr << file << " could not be opened.\n";
      exit(EXIT_FAILURE);
    }
    
    cout << "Enter the record number you wish to change: ";
    long rec;
    cin >> rec;
    eatline();  // get rid of newline
    if (rec < 0 || rec >= ct) {
      cerr << "Invalid record number.\n";
      exit(EXIT_FAILURE);
    }
    streampos place = rec * sizeof pl;  // convert to streampos type
    finout.seekg(place);                // random access
    finout.read((char*)&pl, sizeof pl);
    cout << "Your selec:\n";
    cout << rec << ": " << setw(LIM) << pl.name << ": "
         << setprecision(0) << setw(12) << pl.population
         << setprecision(2) << setw(6)  << pl.g << endl;
    if (finout.eof()) finout.clear();
    cout << "Enter planet name: ";
    cin.get(pl.name, LIM);
    eatline();
    cout << "Enter population: ";
    cin >> pl.population;
    cout << "Enter planet's acceleration of gravity: ";
    cin >> pl.g;
    finout.seekp(place);
    finout.write((char*)&pl, sizeof pl) << flush;  // 刷新输出
    
    if (finout.fail()){
      cerr << "Error on attempted write\n";
      exit(EXIT_FAILURE);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    stdio stddef stdlib unistd

    使用临时文件
    #include
    char* tmpnam(char* pszName);
    生成临时文件名
    tmpnam()函数创建一个临时文件名,将它放在pszName指向的C-风格字符串中。常量L_tmpnam和TMP_MAX (二者都是在cstdio中定义的)限制了文件名包含的字符数以及在确保当前目录中不生成重复文件名的情况下可被调用的最多次数

    内核格式化

      iostream族支持程序与中断之间的I/O,而fstream族使用相同的接口提供程序和文件之间的I/O。C++库还提供了sstream族,它们使用相同的接口提供程序和string对象之间的I/O。也就是说,可以使用于cout 的ostream方法将格式化信息写入到string对象中,并使用istream方法(如getline())来读取string对象中的信息。读取string对象中格式化信息或将格式化信息写入到string对象中被称为内核格式化(incore formatting)。

    #include 
    #include 
    #include 
    
    int main()
    {
      using namespace std;
      ostringstream outstr;  // manages a string stream
      string hdisk;
      cout << "What's the name of your hard disk? ";
      getline(cin, hdisk);   // getline
      int cap;
      cout << "What's its capacity in GB? ";
      cin >> cap;
      // write formatted information to string stream
      outstr << "The hard disk " << hdisk << " has a capacity of "
      << cap << " gigabytes.\n";
      string result = outstr.str();  // save result
      cout << result;                // show contents
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    ...
    string lit = "it was a dark and storm day";
    istringstream instr(lit);  // use buf for input
    string word;
    while(instr >> word)
      cout << word << endl;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    总结

    get() 单字符输入
    getline() 字符串输入

    seekg()和seekp()函数提供对文件的随机存取。这些类方法使得能够将文件指针放置到相对于文件开头、文件尾和当前位置的某个位置。tellg()和tellp()方法报告当前的文件位置。

    获取文件大小

    ifstream fin("planets.dat", ios::in | ios::binary);
    fin.seekg(0, ios::end);
    unsigned long long pos = fin.tellg();
    cout << pos << endl;
    
    • 1
    • 2
    • 3
    • 4

    random.cpp

    
    #include 
    #include 
    #include   // 格式化输出
    #include   // for exit
    
    using namespace std;
    
    const int LIM = 20;
    
    struct planet
    {
      char name[LIM];
      double population;
      double g;
    };
    
    const char* file = "planets.dat";
    inline void eatline()
    {
      while (cin.get() != '\n');
    }
    
    int main()
    {
      planet pl;
      cout << fixed;
    
      fstream finout;
      finout.open(file, ios::in | ios::out | ios::binary);
      int cnt = 0;
      if (finout.is_open()) {
        finout.seekg(0);  // go to beginning
        cout << "Here, contents " << file << " file:\n";
        while (finout.read((char*)&pl, sizeof pl)) {
          cout << cnt++ << ": " << setw(LIM) << pl.name << ": "
          << setprecision(0) << setw(12) << pl.population
          << setprecision(2) << setw(6) << pl.g << endl;
        }
        if (finout.eof()) {
          finout.clear();
        } else {
          cerr << "Error in reading " << file << ".\n";
          exit(EXIT_FAILURE);
        }
      } else {
        cerr << file << " could not be opened.\n";
        exit(EXIT_FAILURE);
      }
      // change a record
      cout << "Enter the record number you wish to change: ";
      long rec;
      cin >> rec;
      eatline();
      if (rec < 0 || rec >= cnt) {
        cerr << "Invalid record number.\n";
        exit(EXIT_FAILURE);
      }
      streampos place = rec * sizeof pl;
      finout.seekg(place);
      if (finout.fail()) {
        cerr << "Error on attempted seek\n";
        exit(EXIT_FAILURE);
      }
      finout.read((char*)&pl, sizeof pl);
      cout << "Your selection:\n";
      cout << rec << ": " << setw(LIM) << pl.name << ": "
          <<  setprecision(0) << setw(12) << pl.population
          <<  setprecision(2) << setw(6) << pl.g << endl;
      if (finout.eof()) {
        finout.clear();
      }
    
      cout << "Enter name: ";
      cin.get(pl.name, LIM);
      eatline();
      cout << "Enter popu: ";
      cin >> pl.population;
      cout << "Enter g: ";
      cin >> pl.g;
      finout.seekp(place);
      finout.write((char*)&pl, sizeof pl) << flush;
      if (finout.fail()) {
        cerr << "Error\n";
        exit(EXIT_FAILURE);
      }
      // show revised file
      cnt = 0;
      finout.seekg(0);  // goto beginning of file
      cout << "Here " << file << " file:\n";
      while (finout.read((char*)&pl, sizeof pl)) {
        cout << cnt++ << ": " << setw(LIM) << pl.name << ": "
            <<  setprecision(0) << setw(12) << pl.population
            <<  setprecision(2) << setw(6) << pl.g << endl;
      }
      finout.close();
      cout << "Done.\n";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98

    writedat.cpp

    #include 
    #include 
    #include   // 格式化输出
    #include   // for exit
    
    const int LIM = 20;
    
    struct planet
    {
      char name[LIM];
      double population;
      double g;
    };
    
    int main()
    {
      using namespace std;
      ofstream fout("planets.dat", ios::out | ios::binary);
      if (!fout) {
        return 0;
      }
      planet p1 = {"earth", 1000, 9.80001};
      planet p2 = {"mars", 34234, 4.555};
      planet p3 = {"moon", 45, 3.55};
      fout.seekp(0);
      fout.write((char*)&p1, sizeof p1);
      fout.write((char*)&p2, sizeof p2);
      fout.write((char*)&p3, sizeof p3);
      fout.close();
      
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
  • 相关阅读:
    统信桌面操作系统PXE单机部署
    scss
    python flask_restful “message“: “Failed to decode JSON object: None“
    中兴B863AV3.1-M2_卡刷固件_萌虎开机动画
    8.strtok函数
    【Python】time模块和datetime模块的部分函数说明
    数据结构之单链表
    【迅搜02】究竟什么是搜索引擎?正式介绍XunSearch
    【生命周期】
    (一)NanoPi m4v2 安装 Home Assistant(含 supervisor)
  • 原文地址:https://blog.csdn.net/surfaceyan/article/details/130232813