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文件:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM