C++打开文本文件的输入校验

Input validation of opening a text file in C++

我正在构建一个输入验证函数,它接受用户的输入并尝试打开该文件。如果用户输入的格式不正确,则重复。正确的格式是:

test1.txt

如果我在第一个 运行 中写入正确的格式,我的函数就可以工作,但在第二个 运行 之后,尽管我正在写入要打开的写入格式,但它仍然打印错误消息。我试图在接受输入后清除输入“cin”和“文件名”,但它没有用。有什么想法吗?

string getFileInput()
{
    string filename;
    fstream file;

    cout << "Please enter the name of the file: ";
    getline(cin, filename);
    file.open(filename.c_str());
    while(!file.is_open())
    {
        file.clear(); file.ignore();
        cout << "File name is incorrect, please enter again: ";
        cin.clear(); cin.ignore();

        getline(cin, filename);
        file.open(filename.c_str());
    }
    // Extra condition. Empty file
    if (file.eof())
    {
        cout << filename << " is an empty file." << endl;
    }
    file.close();
    return filename;
}

我可以重现并修复。

问题是由 cin.ignore() 引起的。根据 cppreference:

... the next available character c in the input sequence is delim

因此 ignore 将读取下一行,直到换行符,并且 保留换行符 。而后面的getline只能读取一个空字符串!

顺便说一句,对 ignoreclear 使用未打开的 fstream (file) 至少是无用的,并且可能是有害的,因为这些方法是预期的在开放流中调用。使用 cin.clear() 也是无用的并且可能是有害的:如果由于任何原因你有一个读取错误(例如因为你到达了文件末尾),你将始终清除错误条件并在你时再次尝试读取应该中止。

最后,eof 条件仅设置 之后,由于文件结束,读取没有返回任何内容。打开空文件时永远不会设置它,也不会成功读取文件末尾。

所以函数应该归结为:

string getFileInput()
{
    string filename;
    fstream file;

    cout << "Please enter the name of the file: ";
    getline(cin, filename);
    if (! cin) {
        // test the error immediately and before using filename!
        cerr << "read error: aborting...\n";
        return "";
    }
    file.open(filename.c_str());
    while(!file.is_open())
    {
        cout << "File name is incorrect, please enter again: ";

        getline(cin, filename);
        if (! cin) {
            // test the error immediately and before using filename!
            cerr << "read error: aborting...\n";
            return "";
        }
        file.open(filename.c_str());
    }
    file.close();
    return filename;
}