Почему stream :: ignore не работает как задумано? - PullRequest
0 голосов
/ 27 октября 2018

Насколько я знаю, stream.ignore (n, 'n') должен игнорировать количество символов (n) или, если достигнуто \ n, и переходить к следующей строке, однако, когда я запускаюследующий код:

// include...
void insertInfo(int info) {
    std::fstream stream("infoFile.txt"); // Open the file
    while (!stream.eof()) {
        std::string a{};
        // getline(stream, a);    <--- Tryied this, didn't work neither
        stream.ignore(99, '\n');
    } // Skip to the last line without any number, in theory
    std::cout << info << std::endl; // Check if the output it's correct (Wich is)
    stream << info; // Insert the info
    stream.close(); // Close the file
}

void main() //Main
{
    std::cout << "Enter your name, followed by the info you want to add to infoFile:" << std::endl;
    std::string info, temp = "";
    std::getline(std::cin, temp); // Get the info input
    std::stringstream sstream;
    sstream << temp;
    sstream >> temp >> info; // Remove the name keeping only the info
    temp = "";              // ^
    std::string::size_type sz;
    insertInfo(stoi(info, &sz)); // Convert info string into an integer and insert it in infoFile
}

Консоль выводит правильное значение «info», однако, когда я проверяю info.txt, в котором я ранее записал «0», вы не видите никаких изменений.Я попытался удалить функцию «игнорировать», и она перезаписывает 0, что я и пытался предотвратить.Я также попытался использовать функцию "getline", но происходит то же самое.В чем здесь ошибка?

1 Ответ

0 голосов
/ 27 октября 2018

Задача

Невозможно записать в файл.

Почему

void insertInfo(int info) {
    std::fstream stream("infoFile.txt"); // Open the file

Открывает файл с разрешениями по умолчанию, включая чтение. Стандарт C ++ говорит, что я должен ожидать поведение "r+" , а стандарт C говорит, что файл, открытый с поведением "r +", должен существовать для чтения (кто-то, пожалуйста, добавьте ссылку, если она у вас есть). Вы не можете создать новый файл. Это проблема 1. Аскер справился с этой проблемой, предоставив файл.

Примечание: будьте осторожны при работе с файлами по относительным путям. Рабочий каталог программы может быть не там, где вы думаете. Это проблема 1а. Похоже, что Аскер об этом позаботился на данный момент.

    while (!stream.eof()) {

Распространенная ошибка. Подробнее см. Почему iostream :: eof внутри условия цикла считается неправильным? В этом случае, поскольку все, что вам нужно, это конец файла, тот факт, что файл не был открыт вообще или столкнулся с какими-либо ошибками чтения пропущен. Так как файл в состоянии ошибки никогда не может достичь конца файла, это быстро становится бесконечным циклом. Это проблема 2.

        std::string a{};
        // getline(stream, a);    <--- Tryied this, didn't work neither
        stream.ignore(99, '\n');

Всегда проверяйте транзакции ввода-вывода на успех. Этот вызов может быть не проверен.

    } // Skip to the last line without any number, in theory

При условии, что ничего не пошло не так, и, поскольку мы не проверяем состояние ошибки, при условии, что все, что мы можем сделать, файл достиг конца и теперь находится в состоянии ошибки EOF. Мы не можем читать или писать в поток, пока мы не clear этой ошибки. Это проблема № 3 и, вероятно, проблема, с которой борется Аскер.

    std::cout << info << std::endl; // Check if the output it's correct (Wich is)
    stream << info; // Insert the info

Это может быть не проверено.

    stream.close(); // Close the file

Это не обязательно. Файл будет закрыт, когда он выйдет из области видимости.

}

Решение

void insertInfo(int info) {
    std::fstream stream("infoFile.txt"); // Open the file
    while (!stream.eof()) {
        stream.ignore(99, '\n');
    } // Skip to the last line without any number, in theory
    std::cout << info << std::endl; // Check if the output it's correct (Wich is)
    stream.clear(); // Added a call to clear the error flags.
    stream << info; // Insert the info
    stream.close(); // Close the file
}

Теперь мы можем записать в файл. Но давайте улучшим это?

void insertInfo(int info) {
    std::fstream stream("infoFile.txt"); 
    while (stream.ignore(99, '\n')) // moved ignore here. now we ignore, then test the result
    {
    } 
    stream.clear();
    stream << info << '\n'; // added a line ending. Without some delimiter the file 
                            // turns into one big number 
}

Обратите внимание, что это не совсем кошерное. Если по какой-либо причине происходит сбой игнорирования, мы выручаем и, возможно, перезаписываем данные, потому что код вслепую clear s и пишет. Я не буду тратить здесь много времени, пытаясь исправить это, потому что мы можем действительно, очень просто и решить проблему создания несуществующего файла одновременно.

void insertInfo(int info) {
    std::fstream stream("infoFile.txt", std::ios::app); 
    stream << info << '\n'; 
}

Две строки и почти все готово. С app мы добавляем файл. Нам не нужно находить конец файла, поток автоматически указывает на него. Если файл не существует, он создается.

Следующее улучшение: сообщите людям, если запись не удалась.

bool insertInfo(int info) {
    std::fstream stream("infoFile.txt", std::ios::app);
    return static_cast<bool>(stream << info << '\n');
}

Если файл не был записан по какой-либо причине, функция возвращает значение false, и вызывающая сторона может выяснить, что делать. Осталось только подтянуть поток. Поскольку все, что мы делаем, это пишем в ti, нам не нужна вседозволенность fstream. Всегда начинайте с самых ограничительных и переходите к минимальным. Это помогает предотвратить некоторые потенциальные ошибки, делая их невозможными.

bool insertInfo(int info) {
    std::ofstream stream("infoFile.txt", std::ios::app);
    return static_cast<bool>(stream << info << '\n');
}

Теперь мы используем ofstream и исключаем все дополнительные издержки и риски, связанные с возможностью чтения потока, когда мы не читаем поток.

...