• C++ 随机访问文件


    顺序访问文件

      一个文件是由一个字节序列构成的。操作系统维护一个叫做文件指针(file pointer)的特殊标记,指向序列中的某个位置。读写操作都是在文件指针指向的位置进行。当文件打开时,文件指针被设置在文件开始位置。当读写数据时,文件指针会移动到下一个数据项。例如,如果使用get()函数读取一个字节,C++从文件指针指向的位置读出一个字节,文件指针会向前移动一个字节,如下图所示:

    (注:前是向文件结尾的方向,而后是向文件开始的方向)

      我们之前写过的程序都是顺读写数据的,即文件指针一直向前移动,这被称为顺序访问文件。如果一个文件以输入的方式打开,将从其文件开始位置向文件结尾读取数据。如果一个文件以输出方式打开,则从其开始位置(默认)或末尾位置(ios::app)开始一个接一个地写入数据项。

    随机访问文件

      顺序访问的问题在于,如果我们想要读取一个特定位置的字节,那么必须读取它前面所有的字节,这样做效率太低了。所以C++引入了随机访问文件的概念,也就是说可以任意地向前或向后移动文件指针,而使用的函数是seekp和seekg函数。

    seekp,即seek put,用于输出流。

    seekg,即seek get,用于输入流。

    seekp和seekg都有两个版本,分别是有一个参数的和有两个参数的。

    一个参数的:参数指出绝对位置,例如:

    input.seekg(0);
    output.seekp(0);

    以上两句代码都将文件指针移动到了文件开始的位置。

    两个参数的:第一个参数是长整数,指出偏移量,正数为向前,负数为向后;第二个参数被称为定位基址(seek base),指出偏移量是相对于哪个位置而偏移的。下表给出了三个支持的定位基址参数。

    定位基址 描述
    ios::beg 偏移量相对于文件开始位置
    ios::end 偏移量相当于文件结尾位置
    ios::cur 偏移量相当于文件指针当前位置

    下表给出一些使用seekp和seekg函数的例子。

    语句 描述
    seekg(100, ios::beg); 将文件指针移动到从文件开始第100个字节处
    seekg(-100, ios::end); 将文件指针移动到文件末尾向后100个字节处
    seekp(42, ios::cur); 将文件指针从当前位置向前移动42个字节
    seekp(-42, ios::cur); 将文件指针从当前位置向后移动42个字节
    seekp(100); 将文件指针移动到文件第100个字节处

    我们可以使用tellp和tellg函数返回文件指针的当前位置。

    下面给出一个例子。这个例子先将4个Student对象写入到student.dat文件中。然后从student.dat文件中读取第三个同学的信息(一个Student对象占据的空间是12,int=4,char=1,但是char占4):

    #include <iostream>
    #include <fstream>
    
    using namespace std;
    class Student {
    public:
        Student(){}
        Student(char name, int age, int score){
            this->age = age;
            this->name = name;
            this->score = score;
        }
        int getAge() const{
            return this->age;
        }
        char getName() const{
            return this->name;
        }
        int getScore() const{
            return this->score;
        }
    private:
        int age;
        char name;
        int score;
    };
    
    void displayStudent(const Student student){
        cout << "学生" << student.getName() << "的年龄是" << student.getAge() << ", 成绩是" << student.getScore() << endl;
    }
    int main()
    {
        fstream binaryio;
        binaryio.open("student.dat", ios::out|ios::binary);
    
        Student student1('A', 10, 10);
        Student student2('B', 11, 20);
        Student student3('C', 10, 30);
        Student student4('D', 12, 100);
    
        binaryio.write(reinterpret_cast<char*>(&student1),sizeof(Student));
        binaryio.write(reinterpret_cast<char*>(&student2),sizeof(Student));
        binaryio.write(reinterpret_cast<char*>(&student3),sizeof(Student));
        binaryio.write(reinterpret_cast<char*>(&student4),sizeof(Student));
    
        binaryio.close();
    
        binaryio.open("student.dat", ios::in|ios::binary);
    
        Student studentNew;
    
        binaryio.seekg(2*sizeof(Student));
    
        cout << "当前文件指针的位置是" << binaryio.tellg() << endl;
    
        binaryio.read(reinterpret_cast<char*>(&studentNew),sizeof(Student));
    
        displayStudent(studentNew);
    
        cout << "当前文件指针的位置是" << binaryio.tellg() << endl;
        binaryio.close();
    
        return 0;
    }

    运行结果:

    student.dat文件:

  • 相关阅读:
    linux常用脚本
    shell学习笔记
    Linux常用命令List
    Centos7部署Zabbix
    centos7安装nagios步骤
    nagios报错HTTP WARNING: HTTP/1.1 403 Forbidden解决方法
    U盘安装CentOS7
    Thread线程控制之sleep、join、setDaemon方法的用处
    EfficientDet框架详解 | 目前最高最快最小模型,可扩缩且高效的目标检测(附源码下载)
    ubuntu18.04 安装多版本cuda ,原来版本为9.0,在新增8.0
  • 原文地址:https://www.cnblogs.com/bwjblogs/p/12944365.html
Copyright © 2020-2023  润新知