• 《好学的C++ 第2版》 第8章 文件-电子存储


    主内存(RAM,随机访问内存)当计算机关闭时其数据就丢失。

    对于cin和cout支持的函数调用和操作,c++提供的文件流也同样支持。前者需要#include <iostream>,后者需要#include <fstream>。流(stream)在写数据时是目的地,读数据时就是源头。

    打开badgirl.txt文件:

    ofstream fout("badgirl.txt"); //以独占方式打开该文件,默认文件在当前目录(运行程序的那个目录),也可给出完整路径(加上驱动器盘符也可以,这就是绝对路径,例如"c:\badgirl.txt"就是c:adgirl.txt文件的绝对路径)。还有ifstream、fstream

    fout << "you bad but sexy girl!" << endl;

    fout << "and you need bad boy!"

    fout.close();

    fout对象提供了一条通向磁盘文件的道路。用面向对象的术语说,fout封装了那个文件并使之具备了接收输出数据的能力。另外,虽然程序成功退出是、时C++会自动关闭仍处於打开状态的文件,但是文件不用时最好及时关闭,使程序放弃对该文件的拥有权,让其他进程可以去访问它。 //it:一个进程打开了某文件,其他进程是否可读可写该文件?试图打开该文件是否会出错?

    char filename[MAX_PATH+1];

    预定义常数MAX_PATH:系统所能支持的文件名(包括其路径在内)的最大长度。

    若文件打开操作不成功,fout就会是NULL,可用于判断。非法路径或者像以写的方式打开只读文件都会返回NULL.

    if(!fout){/*...*/}

    ifstream fin;//文件以文本和输入方式打开。

    fin.getline(input_line, COL_WIDTH+1);//读出一行

    if(fin.eof()){/*...*/};  //到达文件末尾,fin.eof()就是true了

    库函数atoi可以将字符串转为整数,这可以用来处理用户输入。

    以上都是文本流,操作与控制台IO大同小异。写入文件的每一个字节都是可打印字符的ASCII编码。

    二进制文件:读写这类文件时使用的都是数据的实际数值,无需进行ASCII转换(it:数字0就是写入数字0,而不是0的ASCII码值)。

    ####文本模式里,换行符在写时会被转换为 (回车加换行wins)或 (unix)或 (mac)。而二进制模式里无需也不能进行此种转换。####注:回车原意是光标回到当前行的开头,换行原意是光标移动到下一行。所以不要嘲讽wins,含义上是完整的,虽然多一个字符。不过导致的问题就是跨系统的文件格式问题,产生了dos2unix这种命令。

    创建文件流对象时,可将它设置为文本模式(默认)或二进制模式。前者应该使用<<、>>及getline,后者只应该使用read和write成员函数(是直接的读写操作)。

    范例:(记录指的是在文件里不断重复出现的数据格式。由于数据有规律排列,通过记录号获取数据会很容易,而用结构或类来保存它们是很自然的(后续讨论)。)

    #include <iostream>

    #include <fstream>

    using namespace std;

    int get_int(int default_value);

    int main(){

      char filename[MAX_PATH+1];

      int n = 0;

      char name[20];

      int age = 0;

      int recsize = sizeof(name) + sizeof(int);//计算记录的长度

      //打开文件

      cout << "Enter file name: ";

      cin.getline(filename,MAX_PATH);

      fstream fbinout(filename, ios::binary | ios::out); //ios::out是要对文件进行写操作,注意会覆盖现有文件内容,也用于打开新文件

      if(!fbinout){

      cout << "Could not open " << filename <<endl;

      system("PAUSE");

      return -1;

      }

      

      //获取要记录的数据

      cout << "Enter record number: ";

      n = get_int(0);     //获取记录号

      cout << "Enter name: "

      cin.getline(name, sizeof(name));  //获取名字

      cout << "Enter age: ";

      age = get_int(0);         //获取年龄

      

      //写入数据

      fbinout.seekp(n * recsize);   //根据记录号偏移到该记录应在的位置,否则会覆盖0号记录(it:光标或者指针默认的在最开始即0号记录处)

      fbinout.write(name, sizeof(name));

      fbinout.write((char*)(&age),sizeof(int));

      fbinout.close();

      

      system("PAUSE");

      return 0;

    }

    #define COL_WIDTH 80    //80是典型行宽  //it:预编译从定义处开始生效

    int get_int(int default_value){

      char s[COL_WIDTH+1];

      cin.getline(s, COL_WIDTH+1);

      if (strlen(s) == 0)

        return default_value;

      return atoi(s);

    }

    读取数据类似,不同之处只在于:

    fstream fbinin(filename, ios::binary | ios::in); //ios::in模式文件不存在会出错

    fbinin.seekp(n*recsize);

    fbinin.read(name, sizeof(name));

    fbinin.read((char*)(&age), sizeof(int));

    fbinin.close();

    以下fbin将既支持读又支持写:

    fstream fbin(filename, ios::binary | ios::out | ios::in);

    小结捡漏:

    #include <fstream>会将C++标准库提供的文件流支持功能激活(把必要的函数原型和声明引入程序)

    //it:通过文件指针可实现随机访问模式(读写(包括覆盖)文件任意部分而不影响其他数据)。如果文件指针被移动到了超出文件当前长度的位置,文件会自动扩展以满足长度需要。

    seekp成员函数用于移动文件指针,其入参是从文件头开始的偏移量(以字节计算)。

    read和write:入参相同,都是数据地址(char*类型)和需要复制的字节数。//it:写入int要取其地址转为char*类型,但复制字节数仍是int所占用字节数(建议用sizeof获取)。

    fbin.write((char*)(&x), sizeof(x));

  • 相关阅读:
    工具类-vim在shell中卡死的情况
    tomcat日志分类
    逻辑运算
    牛客练习赛29 F 算式子
    牛客练习赛29 B
    查询
    hdu 5984
    zoj 4057
    zoj 4056
    zoj 4054
  • 原文地址:https://www.cnblogs.com/fFaXzz/p/6667114.html
Copyright © 2020-2023  润新知