C++檔案讀寫結構體詳解

2020-07-16 10:04:43
我們知道,一個欄位是與單個專案有關的單塊資訊。而記錄由欄位組成,是關於單個專案的完整資訊集。例如,一組欄位可能是一個人的姓名、年齡、地址和電話號碼,而所有這些與一個人有關的欄位則共同組成了一個記錄。

在 C++ 中,結構體提供了一種將資訊組織到欄位和記錄中的便捷方法。例如,下面的結構體宣告可以用來建立一個包含某人資訊的記錄:
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];
};
除了提供資訊的組織結構之外,結構體還可以將資訊打包成一個單元。例如,假設結構體變數 person 被宣告如下:

Info person;

一旦 person 的成員(或欄位)填充了資訊,則可以使用 write 函數將整個變數寫入一個檔案中:

file.write(reinterpret_cast<char*>(Sperson), sizeof(person));

第一個實參是 person 變數的地址。reinterpret_cast<char*> 轉換操作符是必需的,因為 write 需要第一個實參是一個指向 char 的指標。如果將除 char 之外的其他任何東西的地址傳遞給 write 函數,則必須使用轉換操作符使它看起來像是一個指向 char 的指標。第二個實參是 sizeof 運算子,它告訴 write 有多少個位元組要寫入檔案。

下面的程式演示了這種技術:
//This program demonstrates the use of a structure variable to
//store a record of information to a file.
#include <iostream>
#include <fstream>
#include <cstring>
#include <cctype> // for toupper
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];
};

int main()
{
    Info person; // Store information about a person
    char response; // User response
    string input; // Used to read strings
    // Create file object and open file
    fstream people("people.dat", ios::out | ios::binary);
    if (!people)
    {
        cout << "Error opening file. Program aborting.n";
        return 0;
    }
    // Keep getting information from user and writing it to the file in binary mode
    do {
        cout << "Enter person information:n";
        cout << "Name: ";
        getline (cin, input);
        strcpy(person.name, input.c_str());
        cout << "Age:";
        cin >> person.age;
        cin.ignore(); // Skip over remaining newline
        cout << "Address line 1: ";
        getline(cin, input);
        strcpy(person.address1, input.c_str());
        cout << "Address line 2: ";
        getline(cin, input);
        strcpy(person.address2, input.c_str());
       
        cout << "Phone : ";
        getline(cin, input);
        strcpy(person.phone, input.c_str());
        people.write(reinterpret_cast<char *>(&person), sizeof(person));
        cout << "Do you want to enter another record? ";
        cin >> response;
        cin.ignore();
    } while (toupper(response) == 'Y');
    // Close file
    people.close ();
    return 0;
}
程式輸出結果:

Enter person information:
Name: http://c.biancheng.net
Age:5
Address line 1: no1
Address line 2: no2
Phone : 123456
Do you want to enter another record? N

注意,由於結構可以包含混合的資料型別,所以當開啟一個檔案來儲存它們時,應該總是使用 ios::binary 模式。

此程式允許通過填充 person 變數的成員來建立一個檔案,然後把變數寫入檔案。要將 C 字串讀入一個陣列,則程式首先應使用 getline 函數讀取字串物件,然後使用 strcpy 將 C 字串移動到字元陣列中。下面的程式開啟檔案並將每個記錄讀入 person 變數,然後在螢幕上顯示該資訊:
// 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, PH〇NE_SIZE = 14; struct Info {
    char name[NAME_SIZE];
    int age;
    char addressl[ADDR_SIZE];
    char address2 [ADDR_SIZE];
    char phone[PHONE_SIZE];
};

int main()
{
    Info person; // Store person information
    char response; // User response
    // Create file object and open file for binary reading
    fstream people("people.dat", ios::in | ios:ibinary);
    if (!people)
    {
        cout << "Error opening file. Program aborting.n";
        return 0;
    }
    // Label the output
    cout << "Here are the people in the file:nn";
    // Read one structure at a time and echo to screen
    people.read(reinterpret_cast<char *>(&person), sizeof (person));
    while (!people.eof())
    {
        cout << "Name: ";
        cout << person.name << endl;
        cout << "Age: ";
        cout << person.age << endl;
        cout << "Address line 1: ";
        cout << person.address1 << endl;
        cout << "Address line 2: ";
        cout << person.address2 << endl;
        cout << "Phone: ";
        cout << person.phone << endl;
        cout << "nStrike any key to see the next record.n";
        cin.get (response);
        people.read(reinterpret_cast<char *>(&person), sizeof(person));
    }
    cout << "That's all the information in the file!n";
    people.close();
    return 0;
}
程式輸出結果:

Here are the people in the file:

Name: http://c.biancheng.net
Age: 5
Address line 1: no1
Address line 2: no2
Phone: 123456

Strike any key to see the next record.

That's all the information in the file!

注意,如果結構中包含指標,則使用本節介紹的技術將無法正確儲存到磁碟。這是因為如果在程式的後續執行中將結構讀入記憶體中,則不能保證所有程式變數都位於相同的記憶體位置。由於 string 類物件包含隱式指標,所以它們不能作為將要儲存的結構的一部分。