簡體   English   中英

如何在 c++ 中使用二進制文件輸入/輸出讀取/寫入結構的字符串類型成員?

[英]How to read/write string type member of a struct using binary file in/out in c++?

我有 2 c++ 代碼:一個用於將數據寫入二進制文件,另一個用於讀取該文件。

write.cpp代碼如下:

#include <iostream>
#include <fstream>
using namespace std;
const int NAME_SIZE = 51;
struct Data
{
    char name[NAME_SIZE];
    int age;
};

int main()
{
    Data person;
    char again;

    fstream people("people.db", ios::out | ios::binary);

    do
    {
        cout << "Enter the following data about a "<< "person:\n";
        cout << "Name: ";
        cin.getline(person.name, NAME_SIZE);
        cout << "Age: ";
        cin >> person.age;
        cin.ignore();

        people.write(reinterpret_cast<char *>(&person),sizeof(person));

        cout << "Do you want to enter another record? ";
        cin >> again;
        cin.ignore();
    } while (again == 'Y' || again == 'y');
    people.close();



    return 0;
}

read.cpp代碼如下:

#include <iostream>
#include <fstream>
using namespace std;
const int NAME_SIZE = 51;
struct Data
{
    char name[NAME_SIZE];
    int age;
};

int main()
{
    Data person;
    char again;
    fstream people;

    people.open("people.db", ios::in | ios::binary);

    if (!people)
    {
        cout << "Error opening file. Program aborting.\n";
        return 0;
    }

    cout << "Here are the people in the file:\n\n";
    people.read(reinterpret_cast<char *>(&person),sizeof(person));

    while (!people.eof())
    {
        cout << "Name: ";
        cout << person.name << endl;
        cout << "Age: ";
        cout << person.age << endl;

        cout << "\nPress the Enter key to see the next record.\n";
        cin.get(again);
        people.read(reinterpret_cast<char *>(&person),sizeof(person));
    }
    cout << "That's all the data in the file!\n";
    people.close();
    return 0;
}

上面提到的代碼工作正常。 當我在結構中使用字符串類型成員時出現問題:

新的write.cpp

#include <iostream>
#include <fstream>
using namespace std;

struct Data
{
    string name;
    int age;
};

int main()
{
    Data person;
    char again;

    fstream people("people.db", ios::out | ios::binary);

    do
    {
        cout << "Enter the following data about a "<< "person:\n";
        cout << "Name: ";
        cin>>person.name;
        cout << "Age: ";
        cin >> person.age;
        cin.ignore();

        people.write(reinterpret_cast<char *>(&person),sizeof(person));

        cout << "Do you want to enter another record? ";
        cin >> again;
        cin.ignore();
    } while (again == 'Y' || again == 'y');
    people.close();



    return 0;
}

新的read.cpp

#include <iostream>
#include <fstream>
using namespace std;

struct Data
{
    string name;
    int age;
};

int main()
{
    Data person;
    char again;
    fstream people;

    people.open("people.db", ios::in | ios::binary);

    if (!people)
    {
        cout << "Error opening file. Program aborting.\n";
        return 0;
    }

    cout << "Here are the people in the file:\n\n";
    people.read(reinterpret_cast<char *>(&person),sizeof(person));

    while (!people.eof())
    {
        cout << "Name: ";
        cout << person.name << endl;
        cout << "Age: ";
        cout << person.age << endl;

        cout << "\nPress the Enter key to see the next record.\n";
        cin.get(again);
        people.read(reinterpret_cast<char *>(&person),sizeof(person));
     }
     cout << "That's all the data in the file!\n";
     people.close();
    return 0;
}

現在,當我運行read.cpp時,程序無法讀取字符串並且程序崩潰了。 我必須使用字符串作為結構的成員。 如何解決這個問題呢?

想到的唯一方法是分別寫入以下數據:

  1. 字符串的長度。
  2. 字符串的字符數組。
  3. 年齡。

並分別閱讀。

創建用於寫入/讀取Data實例的函數,以使它們知道彼此的實現策略。

std::ostream& write(std::ostream& out, Data const& data)
{
   size_t len = data.name.size();
   out.write(reinterpret_cast<char const*>(&len), sizeof(len));
   out.write(data.name.c_str(), len);
   out.write(reinterpret_cast<char const*>(&data.age));
   return out;
}

std::istream& read(std::istream& in, Data& data)
{
   size_t len;
   in.read(reinterpret_cast<char*>(&len), sizeof(len));

   char* name = new char[len+1];
   in.read(name, len);
   name[len] = '\0';
   data.name = name;
   delete [] name;

   in.read(reinterpret_cast<char*>(&data.age));
   return in;
}

並與您的第一種方法類似地使用它們。

而不是使用

people.write(reinterpret_cast<char *>(&person),sizeof(person));

采用

write(people, person);

而不是使用

people.read(reinterpret_cast<char *>(&person),sizeof(person));

采用

read(people, person);

一個問題是sizeof(person.Name)不能提供您認為的功能。 無論您分配給person.Name字符串是什么字符,它始終具有相同的大小(在我的情況下為28個字節)。 這是因為std :: string至少包含:

  • 指向實際字符串的指針
  • 其他數據結構以保存可用大小和使用的大小

因此,您無法調用people.write(reinterpret_cast<char *>(&person),sizeof(person)); 字符串的內容不位於&person (它位於std :: string中的指針所指向的位置)

因此,當執行cout << person.name << endl;時會發生什么? 從您的文件中讀取后? 當您將人寫到people.db時,您實際上已經讀取了person.name的字符串指針指向的地址(而不是內容)。 再次從文件中讀取后,這當然不是有效的內存位置。

以下代碼片段可能對您的情況有所幫助。 可以使用定界符和預定義的字符串長度來代替寫入字符串的長度。

constexpr char delimiter = '\0';
constexpr uint32_t maxStringSize = 1024;

struct Data
{
    string name;
    int age;
};

寫入文件時,在字符串后放置一個delimiter
假設我們有一個Data structure {"John", 42}那么我們會這樣寫:

std::ofstream outStream(filename, std::ios::binary);
outStream << structure.name << delimiter << structure.age;
outStream.close();

讀取文件不是寫入的鏡像(不幸的是)。
我們將使用std::ifstream::getline在不知道字符串大小的情況下讀取字符串。 (省略錯誤檢查)

std::ifstream istrm(filename, std::ios::binary);
Data dataRead;

// string input - use a buffer and look for the next delimiter
char* buf = new char[maxStringSize];
istrm.getline(buf, maxStringSize, delimiter);
dataRead.name = std::string(buf);

// the number input
istrm >> dataRead.age;

有關如何讀/寫此struct的向量的靈感,您可以查看我的存儲庫

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM