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
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. ...
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 );
}
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.
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();
}
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 );