2013-05-19 134 views
-1

我試圖從文件讀取我的數據庫。從文件C++讀取數據庫

這裏是我的save_base方法:

void data_base::save_base() 
{ 
    fstream file; 

    file.open("base.dat", ios::in | ios::out | ios::trunc); 

    if(file.good()==true) { 
     node *p = new node(); 
     p=first; 

     while(p) { 
      file << p->content->connect() << ";" << "\n"; 
      p=p->next; 
     } 
     file.close(); 
    }else{ 
    cout << "Err - opening file." << endl; 
    } 
} 

連接方法:

string product::connect() { 

    ostringstream do_string; 
    do_string << lp; 
    string new_lp = do_string.str(); 

    ostringstream do_string1; 
    do_string1 << count; 
    string new_count = do_string1.str(); 

    ostringstream do_string2; 
    do_string2 << prize; 
    string new_prize = do_string2.str(); 

    ostringstream do_string3; 
    do_string3 << vat; 
    string new_vat = do_string3.str(); 

    string connected = type + ";" + new_lp + ";" + name + ";" + new_count + ";" + unit + ";" + new_prize + ";" + new_vat; 
    return connected; 
} 

和read_base方法:

void data_base::read_base() 
{ 
    fstream file; 

    file.open("base.dat", ios::in); 
    if(file.good()==true) 
    { 
     char data_row[50]; 
     int i=1; 
     while(!file.eof()) { 
      file.getline(data_row,100); 

     string data_content[50]; 
     int j = 0; 

     char *buff; 
     buff = strtok (data_row,";"); 
     while (buff != NULL) { 
      data_content[j] = buff; 
      buff = strtok (NULL, ";"); 
      j++; 
     } 
     string type = data_content[0]; 
     int lp; 
     istringstream iss1(data_content[1]); 
     iss1 >> lp; 
     double count; 
     istringstream iss2(data_content[3]); 
     iss2 >> count; 
     double prize; 
     istringstream iss3(data_content[5]); 
     iss3 >> prize; 
     double vat; 
     istringstream iss4(data_content[5]); 
     iss4 >> vat; 

     // Sprawdzamy typ obiektu zapisanego w danym wierszu pliku 
     if(type == "product") 
     { 

      product new_prod(lp, data_content[2], count, data_content[4], prize, vat); 
      product *new_product = new product(new_prod); 
      this->add(new_product); 
     } 
     i++; 
     } 
    file.close(); 
    }else{ 
     cout << "Err opening file." << endl; 
    } 
} 

我加入一些產品數據庫,它工作正常。即使保存到文件也很好。但主要問題是當我試圖從文件讀取數據庫。從文件讀取數據庫工作正常,但最終,應用程序不會自行結束。我認爲還有一些緩衝需要結束。但我不知道它們是靠近哪個或靠近的。

+1

所以,當你看着你的調試器,如果應用程序沒有結束,應用程序停止在哪裏? – Useless

+0

聽起來像你的應用程序被困在無盡的循環中。在調試器中啓動它,當你滿意時,它處於卡住狀態,「中斷」應用程序的執行(Debug Menu-> Break All或類似的東西)。 –

+0

調用堆棧: #0 7755000D \t NTDLL LdrFindResource_U()(C:\ WINDOWS \ SYSTEM32 \ ntdll.dll中:??)! #1 775DF896 \t NTDLL RtlQueryTimeZoneInformation()(C:\ WINDOWS \ SYSTEM32 \ NTDLL。 dll:??) #2 74B4F499 \t ?? ()(??:??) #3 ?? \t ?? ()(??:??) –

回答

0

我看到至少有一個明顯的錯誤,可能會產生未定義的行爲。您正在分配50個字節但最多讀取100個。

char data_row[50]; 
    int i=1; 
    while(!file.eof()) { 
     file.getline(data_row,100); 

我建議在此代碼中將50更改爲100。

+0

當他們需要訪問超過100個字節時,他們再次獲得UB。將其更改爲'std :: string'並改爲使用'std :: getline()'。 –

+0

@CaptainObvlious同意你的觀點,但據我所知,沒有'getline'重載接受'std :: string'。因此使用'std :: string'將涉及不止兩個字符change =) –

+0

請參閱[std :: getline()](http://en.cppreference.com/w/cpp/string/basic_string/getline) –

1

老實說 - 你在這段代碼中遇到了很多問題,我建議你的主要問題是你可能還在封裝中摔角。你的代碼使用了C和C++風格的組合,這些風格保證讓代碼難以閱讀和維護,這就是爲什麼你在這裏,人們都在努力給你答案。

這就是說,這個問題看起來像是在保存你調用的「新節點()」,看起來你會保存......沒有。你不應該在產品中查詢一些現有的價值嗎?編輯:啊 - 不,你現在將它重新分配爲「p = first」。那麼你在前一行分配的節點會發生什麼?

你也有一個潛在的堆棧撞時,你的任何行超過50個字節:

char data_row[50]; 
int i=1; 
while(!file.eof()) { 
    file.getline(data_row,100); 

如果你必須使用字符數組,進入自己使用的sizeof的習慣中:

file.getline(data_row, sizeof(data_row)); 

我花了一些時間來弄清楚istringstream是什麼 - 你想把字符串轉換成數字嗎?比這更簡單,更高效寫成:

unsigned int lp = atoi(data_content[1].c_str()); 
or 
unsigned int lp = strtoul(data_content[1].c_str(), NULL, 10); 

你read_base功能,這是數據庫的一部分,知道WAAAAY太多的數據記錄。你需要讓read_base看起來更像封裝備案人口遠:

void data_base::read_base() 
{ 
    fstream file("base.dat", ios::in); 
    if(file.good() == false) { 
     cout << "Error opening file." << endl; 
     return; 
    } 

    for(size_t rowNo = 0; !file.eof(); ++rowNo) { 
     row* row = data_type::make_object_from_row(file); 
     if(row != nullptr) 
      this->add(row); 
     } 
    } 
} 

您可能需要尋找到了「工廠模式」對如何實現data_row基本類型,可以讓你做到這一點。但總之,您使產品繼承data_type以便上述工作。 DATA_TYPE :: make_object_from_row會讀取行的第一部分和枚舉類型,以便它可以這樣做:

data_type* data_type::make_object_row_row(istream& file) { 
    switch(get_type(file)) { 
     case DATA_TYPE_PRODUCT: return new product(file); 
     case DATA_TYPE_PERSON: return new person(file); 
     default: 
      clog << "invalid type in database: " << type << endl; 
      return nullptr; 
    } 
} 

(這只是一種可能的方法)。

+0

讓我補充一句:如果您打算按照這種方式進行文字處理,您可能需要進一步研究[link](http://www.cplusplus.com/reference/string/string/getline/) 但是你可能還想看看你可以使用imbue()來告訴一個關於分隔符的流,以便知道要查找的方法;而不是空格,所以你可以這樣做: 'product :: read(istream&file){... file >> lp >> name >> ...; }'和'product :: write(ostream&file){... file << lp << separator << name << separator << ...; }' – kfsone