ifstream creates file if it doesn't exist - c++

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.

You need to specify ifstream::in as a second parameter as:
log.open(arg.c_str(), ifstream::in)
You can also do:
std::ifstream log(arg.c_str(), ifstream::in);
and skip the call to open()

Edit with something Linux compatible;
Try opening with fopen before writing. If the file DNE the FILE pointer will be null.
FILE * file;
file = fopen ("myfile.txt","r");
if (file == NULL)
//throw if fopen didn't already.
else
//do stuff with my file

Related

Qt, C++ - Editing an existing INI file from project doesn't work when I need to save it [duplicate]

It's strange, I add desired file into the resources via Add Existing Files..., the file is there. I run qmake ("Build->Run qmake") to make the file available.
The first issue: I can't write anything into the file from output terminal! But when I manually write into the file, the output terminal shows the change every time I run it. Second issue: it still says QIODevice::read: device not open !
Here's my code:
#include <QCoreApplication>
#include <QDebug>
#include <QFile>
#include <QString>
#include <QTextStream>
#include <iostream>
void wFile(QString Filename)
{
QFile nFile(Filename);
QTextStream str(&nFile);
qDebug() << "what do you want to write in the desired file: ";
str.readLine();
if (!nFile.open(QFile::WriteOnly | QFile::Text))
{
qDebug() << "could not open the file";
return;
}
nFile.flush();
nFile.close();
}
void read (QString Filename){
QFile nFile(Filename);
if(!nFile.open(QFile::ReadOnly | QFile::Text))
{
qDebug() << "could not open file for reading";
return;
}
QTextStream in(&nFile);
QString nText = in.readAll();
qDebug() << nText;
nFile.close();
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QString nFilename =":/MyFiles/DocumentArminV.txt";
wFile(nFilename);
read(nFilename);
return a.exec();
}
And here's output terminal of the code:
The files saved in a qresource are read-only since they are part of the executable so you can not write or modify them.
docs:
Currently, Qt always stores the data directly in the executable, even on Windows, macOS, and iOS, where the operating system provides native support for resources. ...

Establishing via code whether console should be saved to a file (and the name of such file)

I know that when a program is executed in the console, one can specify an output file where the console can be saved. For instance, in Windows:
C:\>myprogram.exe > output.txt
However, is there a way to establish via code, i.e. programatically: 1) whether the console should be saved to a file; and 2) the name of the file to which the output should be saved, if any.
I know that I can of course use fprint or std::cout to print each string to a file the same I can do to the console. But for performance sake, I would like to know if it is possible to establish via code that the entire console should be saved to a file.
Yes, you can write code like this:
int main( int argc, char * argv[] ) {
if ( argc > 1 ) {
// there is a filename on the command line
ofstream ofs( argv[1] ); // open named file
// do something with ofs
}
else {
// do something with standard output
}
}
You can use dup2 function (in windows _dup2). It can solve the problem to log to the console exclusively or log to the file exclusively. This is not a solution to log to both.
You can use some logging library (log4cxx, log4cpp, Boost.Log, QDebug, etc.) They should have abilities you need - e.g. log to both console and file.
Solution with dup2/_dup2:
You can open new file, then call dup2 to exchange stdout with that opened file. It can work with c++ streams but I did not try it.
Relevant part of Microsoft example (all checks removed, pleas se original example. I don't have Windows so I can't verify it.)
#include <stdlib.h>
#include <stdio.h>
#include <io.h>
int main(int argc, char ** argv) {
FILE *DataFile;
fopen_s( &DataFile, "data", "w" ); // open file "data" for writing
_dup2( _fileno( DataFile ), 1 ); // exchange "standard output/console" with file "data"
printf("this goes to 'data' file'\r\n"); // print to standard output, but it will be saved to "data" file
fflush( stdout );
fclose( DataFile );
}
Complete linux verified and working C++ example
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <iostream>
int main(int argc, char ** argv) {
FILE *DataFile;
DataFile = fopen( "data", "w" ); // open file "data" for writing
dup2( fileno( DataFile ), 1 ); // exchange "standard output/console" with file "data"
std::cout << "this goes to 'data' file from c++" << std::endl;
fflush( stdout );
fclose( DataFile );
}

C++ ifstream fails to read on BSD Machine

I have a problem with reading lines from a .txt file in C++.
The code is compiled with gmake on a FreeBSD environment.
So here is my code
int main(int argc, char **argv)
{
std::string temp_value_line;
std::string filename = "values.txt";
std::ifstream open_file(filename.c_str());
if (!open_file.is_open()) {
sys_err("Failed to load values from values.txt");
return 0;
}
int counter = 0;
while (!open_file.eof())
{
open_file >> temp_value_line;
str_to_number(common_value[counter], temp_value_line.c_str());
counter++;
}
sys_log(0, "values loaded succsefully");
open_file.close();
}
After building and running the application, there is the specified error message in my error log, so the file is not opened.
I already checked if there is a permissions or naming problem like "values.txt.txt" but everything seems to be okay. I am able to read/modify the file via console editor.
Thanks in advance.

Geting the file size of a system application on windows in C++

I am trying to get the file size of a system application on windows. To test this i have created a test application that tries to get the file size of smss.exe in C:\Windows\System32\smss.exe but it fails with error: ERROR_FILE_NOT_FOUND. The file does actually exist (i have checked). I've also tried different methods for getting the file size, with: FindFirstFile, CreateFile and GetFileSizeEx. But all return the same error. I would also like to read the file contents.
What am i doing wrong?
The code:
// Test.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <iostream>
__int64 getFileSize(LPWSTR filePath)
{
WIN32_FILE_ATTRIBUTE_DATA fad;
if (!GetFileAttributesEx(filePath, GetFileExInfoStandard, &fad))
{
_tprintf(TEXT("\n CAnt get file size for file %s error %d"), filePath, GetLastError());
return 0;
}
LARGE_INTEGER size;
size.HighPart = fad.nFileSizeHigh;
size.LowPart = fad.nFileSizeLow;
return size.QuadPart;
}
int _tmain(int argc, _TCHAR* argv[])
{
_tprintf(TEXT("File size %d "), getFileSize(L"C:\\Windows\\System32\\smss.exe"));
}
As your application is 32-bit, the system redirects your path to go to SysWOW64 instead, where there is no smss.exe. While you have discovered that Wow64DisableWow64FsRedirection disables this redirection, also consider that having a 64-bit program would also do the trick.
Getting the size of a file is already answered here (can't yet add a comment to your question, so I need to write it as an answer):
How can I get a file's size in C++?
std::ifstream::pos_type filesize(const char* filename)
{
std::ifstream in(filename, std::ifstream::in | std::ifstream::binary);
in.seekg(0, std::ifstream::end);
return in.tellg();
}

How to redirect assert output in C++?

Is it possible to redirect assert output to a file when its parameter is false? I know its default behavior is to write a message to stderr, but the following didn't work as I expected:
#include <iostream>
#include <assert>
#include <fstream>
using namespace std;
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
ofstream ofs;
ofs.open("test.txt", ios_base::out);
ofs << "A";
cerr << "B";
cerr.rdbuf(ofs.rdbuf());
cerr << "C";
assert(1 == 2);
return 0;
}
//---------------------------------------------------------------------------
Results in test.txt:
AC
And results in stdout:
B
Assertion failed: 1 == 2, file C:\xxx\Unit1.cpp, line 14
Abnormal program termination
I was expecting that these 2 last lines printed in stdout were in test.txt file though.
I've also tried using, instead of...
cerr.rdbuf(ofs.rdbuf());
the following:
freopen("test.txt", "a", stderr);
but it hasn't worked as well.
I've also seen some posts (as C: how to redirect stderr from System-command to stdout or file?) suggesting dup2 to redirect streams such as stderr, which that is defined in unistd.h. But I'm at Windows using C++Builder and it doesn't seem available.
You can redirect all output to stderr, or any other standard file handle to a file at the start of your program.
freopen( "error.log","w",stderr);
Read about this here:
http://support.microsoft.com/kb/58667
#edit: if the output goes to stdout, then you need to do:
freopen( "error.log","w",stdout );
If you want to append and not overwrite the error.log:
freopen( "error.log","aw",stdout );