0

所以我创建了一个简单的测试应用程序。它的目的是读取或写入文本文件。它正在寻找字符串“固件:”。这个想法是设备将有一个包传输到它并存储,然后激活。我想存储该包的名称(例如:Update1),当我需要时,查询它并取回包名(从文件中读取)。

问题 1:它似乎没有写入文件。 问题2:当我让它写入文件时,如果存在“Firmware:pkgName”行,我如何将pkgName替换为新的包名?

该程序可以运行和编译,因此请随意将其放入 IDE 或文本编辑器中,但它并不能完全满足我的要求。我使用 log.txt 作为我的示例文件来读取。我确信有一种更简单的方法可以做到这一点。我已经有一段时间了,我已经被难住了。

谢谢您的帮助!

#include <cstdlib>
#include <iostream>
#include <string>
#include <fstream>

using namespace std;

int writeFile(string filename, string pkgName);
int readFile(string filename);

int main(void) {
    string filename = "log.txt", userInput, pkgName;
    system("touch log.txt");

    while (true) {
        cout << "Write or Read?\n>>>";
        cin >> userInput;

        if (userInput == "Write") {
            cout << "What's your package name?\n>>>";
            cin >> pkgName;
            writeFile(filename, pkgName);
        } else if (userInput == "Read") {
            readFile(filename);
        } else {
            cout << "Invalid Input";
        }
    }
}

int writeFile(string filename, string pkgName) {
    bool found, exists = true;
    string line, word;
    fstream firmwareFile;
    int pos, size, num = 1;
    firmwareFile.open(filename.c_str(), ios::in | ios::out | ios::app);
    //firmwareFile << "This is a test.";
    if (firmwareFile.is_open()) {
        while (!found) {
            getline(firmwareFile, line);
            pos = line.find("Firmware: ");
            if (pos != string::npos) {
                //Found It
                found = true;
                exists = true;
                size = line.size();
                word = line.substr(10, ((size - pos) + 10));
                cout << word << " is the old package name" << endl;
                //TODO - Replace that with the new package name
                firmwareFile.close();
            } else if (firmwareFile.eof()) {
                //Doesn't Exist
                found = true;
                exists = false;
                cout << "No last firmware package available.\n";
            } else {
                //Still Looking
                found = false;
                cout << "Searching line #" << num <<  endl;
            }
            num++;
            if (!exists) {
                firmwareFile << endl << "Firmware: " << pkgName << endl;
                cout << "Wrote package name to file\n" << endl;
            }
            firmwareFile.close();
        }   
    } else {
        cout << "Unable to open file";
    }
}

int readFile(string filename) {
    bool found;
    string line, word;
    fstream firmwareFile;
    int pos, size, num = 1;
    firmwareFile.open(filename.c_str(), ios::in | ios::out | ios::app);
    if (firmwareFile.is_open()) {
        while (!found) {
            getline(firmwareFile, line);
            pos = line.find("Firmware: ");
            if (pos != string::npos) {
                found = true;
                size = line.size();
                word = line.substr(10, ((size - pos) + 10));
                cout << word << endl;
            } else if (firmwareFile.eof()) {
                found = true;
                cout << "No last firmware package available.\n";
                firmwareFile << endl << "Firmware: ";
            } else {
                cout << "Searching line #" << num << endl;
            }
            num++;
        }
        firmwareFile.close();
    } else {
        cout << "Unable to open file";
        firmwareFile.close();
    }
    firmwareFile.close();
}

这是我的 log.txt 文件的内容(除了包含“固件:”的行之外的所有内容都是微不足道的)

You
Think
It's
Here
But
It's
Not
So
That
Sucks
Doesn't
It
?
Firmware: Update1
I
Hope
You
Caught
It
!
4

4 回答 4

2

出色地。第一个问题,在您的函数写入文件中,您有一个变量found,您可以在一段时间内对其进行测试while (!found) { ... }。问题是当你第一次测试这个变量时,你还没有将它设置为任何值。所以你在那里有未定义的行为。查看其余代码,我认为您应该使用 do while 循环而do { ... } while (!found);不是 while 循环。看起来你在 readFile 中也有同样的问题。

第二个问题恐怕是坏消息。您不能替换文件中的字符串,除非您使用长度完全相同的字符串进行替换。这只是文件在磁盘上组织方式的限制。实现替换的唯一方法是将整个文件读入内存,在内存中进行替换,然后将整个文件写回磁盘。

于 2012-08-02T19:57:03.997 回答
2

@jrok 回答了您的问题 2,但我怀疑您的代码并非每次都编写,因为 found 未初始化,因此未定义,因此一半时间(大约)您的 while 循环根本不会执行。您需要初始化 found 和 exists ,例如:bool found = false, exists = true;

于 2012-08-02T19:58:10.483 回答
0

如果您编写另一个仅更改相关行的文件,则可以简化事情:

std::ifstream cfg("log.txt");
std::ofstream tmp("log.tmp");
std::string line;
std::string pkgName;

while(std::getline(cfg, line)) {
    if (line.find("Firmware:") != std::string::npos) {
        line = "Firmware: " + pkgName; 
    }
    tmp << line << '\n';
}

现在,重命名和删除文件是特定于平台的。如果您想要一个可移植的解决方案,我建议您查看 Boost Filesystem 库。

于 2012-08-02T20:12:12.310 回答
0

如果您必须替换文件的内容(不删除另一个文件并将其重命名为其名称),那么您需要读入整个文件,对内存中的文件进行必要的更改,然后写出内存文件的全部内容到磁盘文件,覆盖它。

如果允许您删除源文件,则执行这些转换会容易得多。你只需要读入你的源文件,打开一个临时文件并写出它,随时进行你需要的任何更改。处理完源文件后,将其删除,并将新文件重命名为与原始源文件相同的名称。

于 2012-08-02T20:05:44.253 回答