2016-06-28 109 views
-1

我讀與<fstream>文件的特定部分,並表示文件中包含這樣的線路:閱讀C++中的文本文件

Name=Cecil 
Age=34 
Born=London 
//etc. 

對於這個例子的目的,可以說,我想將34分配給變量int age。這意味着我必須找到哪一行以Age開頭,然後在等號後提取值34

後來我想在程序中改變這個值,並將其替換爲文件,所以34將成爲例如35,所以我再次需要找到這個文件的特定部分並寫在那裏。

這似乎是一項基本任務,但目前爲止我找不到任何好的例子。也許最好將我的數據存儲爲JSON或XML,併爲此使用一個庫?

+1

閱讀器'ini'可能適合,例如https://github.com/benhoyt/inih或https://github.com/brofield/simpleini – sp2danny

+0

這將是我所需要的,但是我正在努力安裝它。我總是得到'INIReader :: INIReader(std :: string)'的錯誤'未定義的引用。我已將INIReader.h和ini.h文件放入包含庫中,並將mainIRP旁邊的INIReader.cpp文件放入。我使用C :: B。我不知道我錯過了什麼。 – Letokteren

+0

你是否真的編譯並鏈接到'INIReader.cpp'(參見[這裏](http://www.cprogramming.com/compilingandlinking.html)) – sp2danny

回答

0

因爲您的數據看起來像鍵值對,所以這裏是一個面向對象的方式來做到這一點:

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

struct DATA 
{ 
    struct PAIR 
    { 
      string m_szComponentSeparator; 
      string m_szKey; 
      string m_szValue; 
      PAIR() 
      { 
        m_szComponentSeparator = "="; 
      } 
      void Read(ifstream &_inFile) 
      { 
        string szLine; 
        _inFile >> szLine; 
        size_t pos = szLine.find(m_szComponentSeparator); 
        m_szKey = szLine.substr(0, pos); 
        m_szValue = szLine.substr(pos + 1); 
      } 
      void Write(ofstream &_outFile) 
      { 
        _outFile << m_szKey << m_szComponentSeparator << m_szValue << endl; 
      } 
      int To_int() 
      { 
        return atoi(m_szValue.c_str()); 
      } 
      void SetAs_int(int _iValue) 
      { 
        char szBuf[32] = {0}; 
        snprintf(szBuf, sizeof(szBuf), "%d", _iValue); 
        m_szValue = szBuf; 
      } 

    }; 

    PAIR m_stName; 
    PAIR m_stAge; 
    PAIR m_stBorn; 
    void Read(string _szFilepath) 
    { 
      ifstream inFile(_szFilepath.c_str()); 
      m_stName.Read(inFile); 
      m_stAge.Read(inFile); 
      m_stBorn.Read(inFile); 
    } 
    void Write(string _szFilepath) 
    { 
      ofstream outFile(_szFilepath.c_str()); 
      m_stName.Write(outFile); 
      m_stAge.Write(outFile); 
      m_stBorn.Write(outFile); 
    } 
    void Print() 
    { 
      cout << m_stName.m_szKey << m_stName.m_szComponentSeparator << m_stName.m_szValue << endl; 
      cout << m_stAge.m_szKey << m_stAge.m_szComponentSeparator << m_stAge.m_szValue << endl; 
      cout << m_stBorn.m_szKey << m_stBorn.m_szComponentSeparator << m_stBorn.m_szValue << endl; 
    } 
}; 
int main() 
{ 
    string szInputFile = "in.txt"; 
    string szOutputFile = "out.txt"; 

    DATA oData; 
    oData.Read(szInputFile); 
    oData.Print(); 

    int age = oData.m_stAge.To_int(); 
    age = 35; 
    oData.m_stAge.SetAs_int(age); 

    cout << "after modification:" << endl; 
    oData.Print(); 

    oData.Write(szOutputFile); 

    return 0; 
} 

//Output: 
Name=Cecil 
Age=34 
Born=London 
after modification 
Name=Cecil 
Age=35 
Born=London 
+0

任何投下的理由? – sameerkn

+0

儘管我還沒有實現完整的代碼,但你已經給了我一些關於如何解決這個問題的好主意。我用'find()','substr()'和'atoi()'創建了自己的方法。看起來我需要這些功能。 (我不知道是誰投了你的票。) – Letokteren

+0

大概是低估的,因爲只有代碼的答案並不完全有幫助。這是舊的*「發放魚」*。更有價值的答案將包含一個基本原理。理由很重要,以便您知道何時好的建議開始變壞。 – IInspectable

2

這是一個基本的需求,但不是基本的實現,因爲文件只是字節流,沒有結構。這意味着你需要實現一些算法來解釋/解析寫入的數據。你應該知道你不能刪除文件中的某些東西,也不能插入;我的意思是沒有任何一個操作可以實現這個技巧,這對你的情況來說是個問題,因爲如果你想用7代替34,那麼這個信息的長度是不同的,你想刪除一個char(不可能)並替換另一個(這個有可能);當用103替換34時也是如此。這就是爲什麼數據庫用於:讓您輕鬆管理結構化信息。

好吧,這並不意味着這是不可能的,因爲數據庫使用文件。可能是,一開始您可以:讀取全部該文件並將其解析爲內存中的結構化數據,然後管理該數據,並在需要時將數據寫入新文件。如果數據太多,這當然不是一個嚴重的實現。

1

這只是一些常規推理答案最終「也許會更好到...「:

任何簡單的實現都會有些脆弱,但是如果你對輸入文件有很好的控制,並且可能的數據損壞風險不會太多打擾你(即損害會很低,易於恢復/修復),即使更換了字符串,您也可能會失去它,搜索「Age = 34 \ n」並將其替換爲「Age = 35 \ n」(如果只有單個Age行文件,否則你需要先找到正確的人)......先將整個文件讀入內存,然後在更換後寫回。

去JSON會給你比結構更安全(沒有機會偶然改變「CarnAge = 34」而不是「年齡= 34」),但JSON仍然可以在純文本編輯器中編輯(如果你小心足夠)。 JSON也是與Web服務交換數據的非常流行的方式。此段也適用於XML,儘管在純文本編輯方面,我認爲JSON對於非程序員來說更容易學習。所以「ini」會這樣做,但我仍然更喜歡JSON。

最後,如果這是更嚴重的事情,考慮一些數據庫會很有意義。這些都是經過驗證的解決方案,可以非常有效地存儲/修改/獲取數據,對於文件I/O而言,效率要比原始讀/寫整個文件更高效(數據庫處理文件的方式只能通過覆蓋部分內容來修改內容,通過保留周圍的儲備空間並具有完全重構某些文件的一部分的機制)。另外大部分數據庫都是ACID,因此可以免費爲您的應用程序增加額外的健壯性。你不能以純文本編輯數據(但你仍然可以在一些表格中準備數據,並通過一些數據庫管理器工具導入它們)。我可以想到的唯一原因是:1)性能(在特殊情況下,優秀的程序員將勝過專業的數據庫引擎,但大多數時候不值得花費巨大的精力) ,2)項目太小/教程,因此,例如「sqlite」的集成並不難,只需讀取整個文件並替換字符串就更簡單了。但是比如我寫我的C++帶U ++框架項目,因此增加SQL將是一些額外的線微風,沒有巨大的麻煩......

+0

謝謝你的深思熟慮回答!使用數據庫會很好,但是項目非常小,並且設置數據庫不在範圍內。我想我會採納你的建議,並且當我想修改一個值時,我現在用編輯後的字符串重新創建整個文件。 – Letokteren

0

試試這個

ifstream ifs("e:\\file.txt"); 
vector<string> file;  
string temp; 

while(getline(ifs, temp)) 
{ 
    if(temp.compare(0,4,"Age=")==0) 
     temp.replace(0, sizeof("Age=125"),"Age=125"); 

     file.push_back(temp); 
} 
ifs.close(); 

ofstream ofs("e:\\file.txt"); 
for(auto begin = file.begin(), end = file.end(); begin!=end; begin++) 
    ofs << *begin << endl; 

ofs.close();