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
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).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With