C++ seekp和seekg函數用法詳解

2020-07-16 10:04:43
檔案流物件有兩個成員函數,分別是 seekpseekg。它們可以用於將讀寫位置移動到檔案中的任何位元組。

seekp 函數用於已經開啟要進行輸出的檔案,而 seekg 函數則用於已經開啟要進行輸入的檔案。可以將 "p" 理解為 "put",將 "g" 理解為 "get",這樣理解當然是有根據的,因為 seekp 可用於將資訊 put(放入)到檔案中,而 seekg 則可用於從檔案中 get(獲取)資訊。

以下是 seekp 的用法範例:

file.seekp(20L, ios::beg);

第一個實參是一個 long 型別的整數,表示檔案中的偏移量。這就是想要移動到的位元組數。在該範例中,使用的是 20L(請記住,L 字元可以強制編譯器將該數位視為一個 long 型別的整數)。該語句可以將檔案的寫入位置移動到編號為 20 的位元組(所有編號從 0 開始,因此編號為 20 的位元組實際上是第 21 個位元組)。

第二個實參稱為模式標誌,它指定從哪裡計算偏移量。標誌 ios::beg 表示偏移量是從檔案開頭算起的。也可以修改該引數,從檔案末尾或檔案中的當前位置計算偏移量。表 1 列出了所有 3 種隨機存取模式的標誌。

表 1 檔案定位標誌
模式標誌 描 述
ios::beg 從檔案頭開始計算偏移量
ios::end 從檔案末尾開始計算偏移量
ios::cur 從當前位置開始計算偏移量

表 2 顯示了 seekp 和 seekg 使用不同模式標誌的範例。

表 2 檔案尋找操作
語 句 如何影響讀/寫位置
file.seekp(32L, ios::beg); 將寫入位置設定為從檔案開頭開始的第 33 個位元組(位元組 32)
file.seekp(-10L, ios::end); 將寫入位置設定為從檔案末尾開始的第 11 個位元組(位元組 10)
file.seekp(120L, ios::cur); 將寫入位置設定為從當前位置開始的第 121 個位元組(位元組 120)
file.seekg(2L, ios::beg); 將讀取位置設定為從檔案開頭開始的第 3 個位元組(位元組 2)
file.seekg(-100L, ios::end); 將讀取位置設定為從檔案末尾開始的第 101 個位元組(位元組 100)
file.seekg(40L, ios::cur); 將讀取位置設定為從當前位置開始的第 41 個位元組(位元組 40)
file.seekg(0L, ios:rend); 將讀取位置設定為檔案末尾

請注意,表 2 中的一些範例使用了負偏移量。負偏移量導致讀或寫位置在檔案中向後移動,而正偏移量則導致向前移動。

假設檔案 letters.txt 中包含以下資料:

Byte 5 from beginning: f
Byte 10 from end: q
Byte 3 from current: u

下面的程式使用了 seekg 函數跳轉到 letters.txt 檔案中的不同位置,每次停止後都檢索一個字元:
//This program demonstrates the seekg function.
#include <iostream>
#include <fstream>
using namespace std;

int main()
{
    // Variable to access file
    char ch;
    // Open the file for reading
    fstream file ("letters.txt", ios::in);
    if (!file)
    {
        cout << "Error opening file.";
        return 0;
    }
    // Get fifth byte from beginning of alphabet file
    file.seekg(5L, ios::beg);
    file.get(ch);
    cout << "Byte 5 from beginning: " << ch << endl;
    // Get tenth byte from end of alphabet file
    file.seekg(-10L, ios::end);
    file.get(ch);
    cout << "Byte 10 from end: " << ch << endl;
    //Go forward three bytes from current position
    file.seekg(3L, ios::cur);
    file.get(ch);
    cout << "Byte 3 from current: " << ch << endl;
    // Close file
    file.close ();
    return 0;
}
程式輸出結果:

Byte 5 from beginning: f
Byte 10 from end: q
Byte 3 from current: u

下面的程式顯示了 seekg 函數的另一個例子。它開啟了包含兩個記錄的 people.dat 檔案。該程式首先顯示記錄 1(第二條記錄),然後顯示記錄 0。
// This program demonstrates the use of a structure
// variable to read a record of information from a file.
#include <iostream>
#include <fstream>
using namespace std;
const int NAME_SIZE = 51, ADDR_SIZE = 51, PHONE_SIZE = 14;

//宣告記錄的結構
struct Info
{
    char name[NAME_SIZE];
    int age;
    char address1[ADDR_SIZE];
    char address2[ADDR_SIZE];
    char phone[PHONE_SIZE];
};

// Function Prototypes
long byteNum(int);
void showRec(Info);

int main()
{
    // Person information
    Info person;
    // Create file object and open the file
    fstream people("people.dat", ios::in | ios::binary);
    if (!people)
    {
        cout << "Error opening file. Program aborting.n"; return 0;
    }
    // Skip forward and read record 1 in the file
    cout << "Here is record 1:n";
    people.seekg(byteNum(1), ios::beg);
    people.read(reinterpret_cast<char *>(&person), sizeof (person));
    showRec(person);
    // Skip backwards and read record 0 in the file
    cout << "nHere is record 0:n";
    people.seekg(byteNum(0), ios::beg);
    people.read(reinterpret_cast<char *>(&person), sizeof (person));
    showRec(person);
    // Close the file
    people.close();
    return 0;
}
long byteNum(int recNum)
{
    return sizeof (Info) * recNum;
}
void showRec(Info record)
{
    cout << "Name:";
    cout << record.name << endl;
    cout << "Age: ";
    cout << record.age << endl;
    cout << "Address line 1: ";
    cout << record.address1 << endl;
    cout << "Address line 2: ";
    cout << record.address2 << endl;
    cout << "Phone: ";
    cout << record.phone << endl;
}
程式螢幕輸出結果:

Here is record 1:
Name:cyuyan
Age: 20
Address line 1: No.1
Address line 2: No.2
Phone: 12345678

Here is record 0:
Name:http://c.biancheng.net
Age: 5
Address line 1: No.1
Address line 2: No.2
Phone: 123456

該程式除了 main 以外還有兩個重要的函數。第一個是 byteNum,它釆用一個記錄編號作為實參,並返回該記錄的起始位元組。它通過將記錄編號乘以 Info 結構的大小來計算記錄的起始位元組。這將從檔案的開始處返回該記錄的偏移量。第二個函數是 showRec,它接收一個 Info 結構作為實參,並在螢幕上顯示其內容。