2010-11-29 58 views
1

我已閱讀了Stack Overflow和其他一些關於將向量寫入文件的網站的幾篇文章。我已經實現了我感覺的工作,但我遇到了一些麻煩。結構中的一個數據成員是一個類字符串,並且在重新讀入該向量時,該數據將丟失。另外,在編寫第一次迭代之後,其他迭代會導致malloc錯誤。如何修改下面的代碼以實現我想要的將矢量保存到文件的能力,然後在程序再次啓動時再讀入它?目前,讀取是在構造函數中寫入一個只有數據成員是矢量的類的析構函數中完成的,但它具有操作該矢量的方法。讀取和寫入結構向量的文件

這是我讀/寫方法的要點。假設vector<element> elements ...

閱讀:

ifstream infile; 
infile.open("data.dat", ios::in | ios::binary); 
infile.seekg (0, ios::end); 
elements.resize(infile.tellg()/sizeof(element)); 
infile.seekg (0, ios::beg); 
infile.read((char *) &elements[0], elements.capacity()*sizeof(element)); 
infile.close(); 

寫:

ofstream outfile; 
outfile.open("data.dat", ios::out | ios::binary | ios_base::trunc); 
elements.resize(elements.size()); 
outfile.write((char *) &elements[0], elements.size() * sizeof(element)); 
outfile.close(); 

STRUCT元件:

struct element { 
int id; 
string test; 
int other;   
}; 
+0

你用什麼C++學習資料告訴你這樣做文件訪問? – 2010-11-29 01:18:41

+0

這是一項家庭作業的一部分,它要求我們使用fstream將矢量數據讀/寫到文件中。由於我們沒有完全覆蓋向班級中的文件進行復雜的矢量寫入,因此我閱讀了fstream文檔等,並在線查看了示例。我決定用二進制文字編寫是最簡單的方法。調整大小等某些細節是我選擇要限制的文件大小。我們沒有正式的書或教材。我們有一些在線筆記,但它們並不像實現我所需要的那麼詳細。 – 2010-11-29 01:38:24

回答

6

在C++中,存儲器通常不能直接讀出和寫入到直接像這樣的磁盤。特別是,您的struct element包含一個string,這是一個非POD數據類型,因此無法直接訪問。

思想實驗可能有助於澄清這一點。您的代碼假定您的所有element值都是相同的大小。如果其中一個string test值比您所假設的長,會發生什麼情況?在讀取和寫入磁盤時,代碼如何知道使用什麼大小?

有關如何處理此問題的更多信息,您需要閱讀serialization

1

您的代碼假定所有相關數據都直接存在於矢量內部,而字符串是固定大小的對象,它們具有可以在堆上添加其可變大小內容的指針。你基本上是保存指針而不是文本。您應該寫一些字符串序列化代碼,例如:

bool write_string(std::ostream& os, const std::string& s) 
{ 
    size_t n = s.size(); 
    return os.write(n, sizeof n) && os.write(s.data(), n); 
} 

然後您可以爲您的結構編寫序列化例程。有幾個設計方案: - 很多人都喜歡聲明Binary_IStream/Binary_OStream類型,可以容納一個std :: ostream的,但作爲一個獨特的類型可以用來創建ALA一組單獨的序列化例程:

operator<<(Binary_OStream& os, const Some_Class&); 

或者,您可以在處理二進制序列化時放棄通常的流式符號,並使用函數調用符號代替。顯然,讓相同的代碼正確輸出二進制序列化和人類可讀序列化是很好的,所以基於操作員的方法很有吸引力。

如果您序列化數字,您需要決定是以二進制格式還是ASCII格式。對於需要可移植性的純二進制格式(甚至在同一操作系統上的32位和64位編譯之間),您可能需要花費一些努力來編碼和使用類型大小元數據(例如int32_t或int64_t?)作爲字節序(例如考慮網絡字節順序和ntohl() - 家族函數)。使用ASCII碼可以避免一些考慮因素,但長度可變,寫入/讀取速度較慢。下面,我隨意使用ASCII和'|'數字終結者。

bool write_element(std::ostream& os, const element& e) 
{ 
    return (os << e.id << '|') && write_string(os, e.test) && (os << e.other << '|'); 
} 

然後爲載體:

os << elements.size() << '|'; 
for (std::vector<element>::const_iterator i = elements.begin(); 
    i != elements.end(); ++i) 
    write_element(os, *i); 

要閱讀此回:

std::vector<element> elements; 
size_t n; 
if (is >> n) 
    for (int i = 0; i < n; ++i) 
    { 
     element e; 
     if (!read_element(is, e)) 
      return false; // fail 
     elements.push_back(e); 
    } 

...這就需要...

bool read_element(std::istream& is, element& e) 
{ 
    char c; 
    return (is >> e.id >> c) && c == '|' && 
      read_string(is, e.test) && 
      (is >> e.other >> c) && c == '|'; 
} 

...和...

bool read_string(std::istream& is, std::string& s) 
{ 
    size_t n; 
    char c; 
    if ((is >> n >> c) && c == '|') 
    { 
     s.resize(n); 
     return is.read(s.data(), n); 
    } 
    return false; 
}