将随机生成的密码保存到文本文件中以便稍后显示

Saving randomly generated passwords to a text file in order to display them later

我目前正在接受培训,目前我必须使用我正在使用的软件。最重要的是昨天请求的,我一直坚持它的主要功能失败:保存密码

该应用程序是使用 Visual Studio 2013 在 C++\CLR 中开发的(无法以某种方式安装 MFC 库,即使在多次重新启动后安装仍然失败和崩溃。)并且旨在从提供的种子生成密码由用户。生成的密码将保存到 .txt 文件中。如果种子已被使用,那么之前生成的密码将显示。

不幸的是,我无法将密码和种子保存到文件中,尽管我可以写入种子 if 我没有读到文档的末尾。我选择了 "if line is empty then write this to the document" 但它不起作用,我也不知道为什么。但是我可以毫无问题地读取密码。

这是源代码中有趣的部分:

int seed;
char genRandom() {
    static const char letters[] =
        "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz";
    int stringLength = sizeof(letters) - 1;
    return letters[rand() % stringLength];
}
System::Void OK_Click(System::Object^  sender, System::EventArgs^  e) {
    fstream passwords;
    if (!(passwords.is_open())) {
        passwords.open("passwords.txt", ios::in | ios::out);
    }
    string gen = msclr::interop::marshal_as<std::string>(GENERATOR->Text), line, genf = gen;
    bool empty_line_found = false;
    while (empty_line_found == false) {
        getline(passwords, line);
        if (gen == line) {
            getline(passwords, line);
            PASSWORD->Text = msclr::interop::marshal_as<System::String^>(line);
            break;
        }
        if (line.empty()) {
            for (unsigned int i = 0; i < gen.length(); i++) {
                seed += gen[i];
            }
            srand(seed);
            string pass;
            for (int i = 0; i < 10; ++i) {
                pass += genRandom();
            }
            passwords << pass << endl << gen << "";
            PASSWORD->Text = msclr::interop::marshal_as<System::String^>(pass);
            empty_line_found = true;
        }
    }
}

我也试过用 ios::app 替换 ios::in 但它不起作用。是的,我已经包含了 fstream、iostream 等

提前致谢!

[编辑] 刚刚解决了这个问题。感谢 Rook 让我走上了正确的道路。感觉这样做很愚蠢,但我关闭了文件并使用 ios::app 重新打开它以在其末尾写入。我还解决了一个愚蠢的错误,该错误导致在种子之前写入密码并且没有插入最后一行,因此主循环仍然可以工作。这是代码,以防有人遇到同样的问题:

int seed;
char genRandom() {
    static const char letters[] =
        "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz";
    int stringLength = sizeof(letters) - 1;
    return letters[rand() % stringLength];
}
System::Void OK_Click(System::Object^  sender, System::EventArgs^  e) {
    fstream passwords;
    if (!(passwords.is_open())) {
        passwords.open("passwords.txt", ios::in | ios::out);
    }
    string gen = msclr::interop::marshal_as<std::string>(GENERATOR->Text), line, genf = gen;
    bool empty_line_found = false;
    while (empty_line_found == false) {
        getline(passwords, line);
        if (gen == line) {
            getline(passwords, line);
            PASSWORD->Text = msclr::interop::marshal_as<System::String^>(line);
            break;
        }
        if (line.empty()) {
            passwords.close();
            passwords.open("passwords.txt", ios::app);
            for (unsigned int i = 0; i < gen.length(); i++) {
                seed += gen[i];
            }
            srand(seed);
            string pass;
            for (int i = 0; i < 10; ++i) {
                pass += genRandom();
            }
            passwords << gen << endl << pass << endl << "";
            PASSWORD->Text = msclr::interop::marshal_as<System::String^>(pass);
            empty_line_found = true;
        }
    }
    passwords.close();
}

所以,这是一件有趣的事情:

passwords << pass << endl << gen << "";

您不会以换行符结束它。这意味着您文件的最后 也可能 缺少换行符。当您在最后一行执行此操作时,这会产生有趣的效果:

getline(passwords, line);

getline 将读取直到看到行结束或 EOF。如果没有换行符,它将到达那个 EOF,然后在流上设置 EOF 位。这意味着下次您尝试这样做时:

passwords << pass << endl << gen << "";

流将拒绝写入任何内容,因为它处于 eof 状态。您可以在此处执行各种操作,但最简单的是执行 passwords.clear() 以删除任何错误标志,如 eof。不过,对于意外清除真正的错误标志,我会非常谨慎;仔细阅读 fstream 的文档。

我还重申我关于 C++/CLR 是一种胶水语言的评论,而不是一种用于通用开发的优秀语言,最好使用 C++ 或 .net 语言(例如 C#)来完成。如果您出于某种原因完全依赖于 C++/CLR,那么您也可以使用广泛的 .net 库,这样您就不必来回毫无意义地管理类型。例如,参见 System::IO::FileStream