简体   繁体   中英

Why is stream::ignore not working as intended?

As far as I know, stream.ignore(n, 'n') should ignore an (n) amount of characters or if '\\n' is reached, and skip over to the next line, however, when I run the next code:

// include...
void insertInfo(int info) {
    std::fstream stream("infoFile.txt"); // Open the file
    while (!stream.eof()) {
        std::string a{};
        // getline(stream, a);    <--- Tried this, didn't work either
        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 (Which 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
}

The console prints out the "info" correct value, however, when I check info.txt, in which I previously wrote a '0' on, you don't see any change. I tried removing the "ignore" function and it overwrites the 0, which is exactly what I was trying to prevent. I also tried using "getline" function but the same thing happens. What is the error here?

Problem

Cannot write to file.

Why

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

Opens file with default permissions, which includes reading. The C++ Standard says I should expect "r+" behaviour and the C Standard says a file opened with "r+" behaviour must exist in order to be read (Someone please add a link if you have one). You cannot create a new file. This is problem 1. The Asker has dealt with this problem by providing a file.

Note: take care when working with files via relative paths. The program's working directory may not be where you think it is. This is problem 1a. It appears that the Asker has this taken care of for the moment.

    while (!stream.eof()) {

Common bug. For more details see Why is iostream::eof inside a loop condition considered wrong? In this case since all you're looking for is the end of the file, the fact that the file hasn't been opened at all or has encountered any read errors is missed. Since a file in an error state can never reach the end of the file this quickly becomes an infinite loop. This is problem 2.

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

Always test IO transactions for success. This call can fail unchecked.

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

Assuming nothing has gone wrong, and since we're not checking the error state assuming's all we can do, the file has reached the end and is now in the EOF error state. We can't read from or write to the stream until we clear this error. This is problem number 3 and likely the problem the Asker is struggling with.

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

This can fail unchecked.

    stream.close(); // Close the file

This is not necessary. The file will be closed when it goes out of scope.

}

Solution

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
}

Now we can write to the file. But let's improve this shall we?

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 
}

Note that this isn't exactly kosher. If any ignore fails for any reason, we bail out and possibly write over data because the code blindly clear s and writes. I'm not spending much time here trying to patch this up because we can get really, really simple and solve the problem of creating a non-existent file at the same time.

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

Two lines and pretty much done. With app we append to the file. We do not need to find the end of the file, the stream automatically points at it. If the file does not exist, it is created.

Next improvement: Let people know if the write failed.

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

If the file was not written for any reason, the function returns false and the caller can figure out what to do. The only thing left is to tighten up the stream. Since all we do is write to ti we don't need the permissiveness of a fstream . Always start with the most restrictive and move to the least. This helps prevent some potential errors by making them impossible.

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

Now we use an ofstream and eliminate all the extra overhead and risk brought in by the ability to read the stream when we don't read the stream.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM