ifstream creates file if it doesn't exist

13,637

Solution 1

You can set the failbit in the exceptions flag for the ifstream:

std::ifstream log;
log.exceptions ( std::ifstream::failbit );
try {
    log.open ("test.txt");
}
catch (std::ifstream::failure e) {
    std::cout << "Exception opening/reading file\n";
}

Source

I've tested, and ifstream will throw a failure exception if the file cannot be opened, e.g. file not found, no read permissions. It will open read-only.

Solution 2

Since you are opening an std::ifstream it is necessary to add std::ios_base::in (or any other spelling of the std::ios_base::openmode) according to 27.9.1.9 [ifstream.members] paragraph 4: The flag is automatically added by the call to open(). Note that an std::ofstream or an std::fstream would automatically add std::ios_base::out (27.9.1.13 [ofstream.members] paragrpah 3) or std::ios_base::in | std::ios_base::out (27.9.1.17 [fstream.members] paragraph 3), both of which resulting in a new file being created if it doesn't exist (and there are write permissions, etc.).

If the code you posted creates a new file, the implementation of the standard C++ library is wrong: when only the flag std::ios_base::in is specified, the file is open "as if" using the open mode "r" with fopen() (27.9.1.4 [filebuf.members] paragraph 5). fopen() in turn doesn't create a new file when it gets an open mode of "r" (7.21.5.3 paragraph 3).

Share:
13,637
Jean-Marie Comets
Author by

Jean-Marie Comets

By day: I write hardcore C++ code to handle market data. By night: I try my best to work on as many Rust projects I can. Currently I'm trying to lend a hand with petgraph.

Updated on June 04, 2022

Comments

  • Jean-Marie Comets
    Jean-Marie Comets almost 2 years

    I'm having some trouble writing a Linux console app which reads apache logs.

    I need to handle bash script arguments, the last one being a path to the log file. My problem is that if the file doesn't exist, I would like to throw an exception.

    But when I try to open the file in read-only mode, instead of failing it creates the file !

    Here's the code :

    // logreader.h
    
    #include <string>
    #include <sstream>
    #include <iostream>
    #include <fstream>
    #include <stdexcept>
    
    
    class LogReader
    {
        public:
            LogReader(int, const char **);
            virtual ~LogReader();
    
            // ...
    
        private:
            std::ifstream log_;
    };
    
    // logreader.cpp
    
    #include <logreader.h>
    
    LogReader::LogReader(int argc, const char ** argv):
        log_()
    {
        log_.exceptions(std::ifstream::failbit | std::ifstream::badbit);
        for (int i = 1; i < argc; ++i)
        {
            std::string arg(argv[i]);
            if (i == argc - 1)
            {
                try
                {
                    log_.open(arg.c_str(), std::ifstream::in);
                }
                catch (std::ifstream::failure)
                {
                    throw std::runtime_error("The file " + arg + " wasn't opened");
                }
            }
        }
    }
    
    LogReader::~LogReader()
    {
    }
    
    // main.cpp
    
    #include <logreader.h>
    
    int main(int argc, const char ** argv)
    {
        LogReader(argc, argv);
        return 0;
    }
    

    Script call:

    jmcomets $ ./test -g -l
    jmcomets $ ls -l
    -rw-rw-r-- 1 jmcomets jmcomets     0 Nov 14 22:41 -l