在 C++ 中读取文本文件的特定部分

Reading a specific part of a text file in C++

我正在读取带有 <fstream> 的文件,并且该文件包含如下行:

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

为了示例,假设我想将 34 分配给变量 int age。这意味着我必须找到哪一行以 Age 开头,然后提取等号后的值 34

稍后我想在程序中改变这个值,并在文件中替换它,所以 34 会变成例如 35,所以再次,我必须找到这个特定的文件的一部分并写在那里。

这似乎是一项基本任务,但到目前为止我找不到任何好的例子。也许将我的数据存储为 JSON 或 XML 并为此目的使用库会更好?

这是基本需求,但不是基本实现,因为文件只是字节流,没有结构。这意味着您需要对写入的数据实施某种算法 interpret/parse 。您应该知道您不能删除文件中的内容,也不能插入;我的意思是没有单一的操作可以解决问题,这在您的情况下是个问题,因为如果您想用 7 替换 34,则该信息的长度不同并且您想删除一个字符(不可能)并替换另一个(这个有可能);将 34 替换为 103 时也是同样的道理。这就是数据库的用途:让您轻松管理结构化信息。

好的,这并不意味着这是不可能的,因为数据库使用文件。可能是,初步估计您可以:读取 all 文件并将其解析为内存中的结构化数据,然后管理该数据并在需要时将数据写入新文件。当然,如果你有太多数据,这不是一个认真的实现。

由于您的数据看起来像键值对,因此这是一种面向对象的方法:

#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

这只是一些一般性的推理,作为对最终答案的回答 "Maybe it would be better to ...":

任何简单的实现都会有点脆弱,但如果您对输入文件有很好的控制,并且可能的数据损坏风险不会太困扰您(即损坏会很低且容易restore/repair),即使进行字符串替换,搜索 "Age=34\n" 并将其替换为 "Age=35\n"(如果文件中只有一条年龄线,否则您需要先找到正确的人),您也可能逃脱。 ..首先将整个文件读入内存,然后在替换后将其写回。

选择 JSON 将使您在结构上更加安全(不会意外更改 "CarnAge=34" 而不是 "Age=34"),但 JSON 仍然是可编辑的在纯文本编辑器中(如果你足够小心的话)。 JSON 也是与 Web 服务交换数据的一种非常流行的方式。本段也适用于 XML,尽管就纯文本编辑而言,我认为 JSON 对于非程序员来说更容易学习。所以 "ini" 可以,但我还是更喜欢 JSON.

最后,如果这更严重,考虑一些数据库将很有意义。这些是经过验证的解决方案,可以非常有效地 store/modify/fetch 数据,文件 I/O 比天真的 read/write 整个文件更有效(数据库正在处理文件,允许他们通过仅覆盖来修改内容它的一部分,通过保留保留 space 并具有完全重组某些文件的一部分的机制)。此外,大多数数据库都是 ACID,因此可以为您的应用增加额外的稳健性 "for free"。您只是无法编辑纯文本数据(但您仍然可以在某些 sheet 中准备数据,并通过某些数据库管理器工具导入它们)。

我能想到的避免使用某些常见数据库的唯一原因是:1) 性能(在特殊情况下,优秀的程序员会胜过专业的数据库引擎,但大多数时候不值得付出巨大的努力), 2) 项目太 small/tutorial,所以虽然集成例如 "sqlite" 并不难,但读取整个文件并替换字符串就更简单了。但是例如我用 U++ 框架编写我的 C++ 项目,所以添加 SQL 将是几行额外的轻而易举的事,没有大麻烦...

试试这个

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();