How to write console data into a text file in C++? - c++

I'm working on a file sharing application in C++. I want to write console output into a separate file and at the same time I want to see the output in console also. Can anybody help me...Thanks in advance.

Here we go...
#include <fstream>
using std::ofstream;
#include <iostream>
using std::cout;
using std::endl;
int main( int argc, char* argv[] )
{
ofstream file( "output.txt" ); // create output file stream to file output.txt
if( !file ) // check stream for error (check if it opened the file correctly)
cout << "error opening file for writing." << endl;
for( int i=0; i<argc; ++i ) // argc contains the number of arguments
{
file << argv[i] << endl; // argv contains the char arrays of commandline arguments
cout << argv[i] << endl;
}
file.close(); // always close a file stream when you're done with it.
return 0;
}
PS: OK, read your question wrong (console output/input mixup), but you still get the idea I think.

The idea is to create a derivate of std::streambuf which will output data to both the file and cout. Then create an instance of it and use cout.rdbuf(...);
Here is the code (tested with MSVC++ 2010, should work on any compiler):
class StreambufDoubler : public std::streambuf {
public:
StreambufDoubler(std::streambuf* buf1, std::streambuf* buf2) :
_buf1(buf1), _buf2(buf2), _buffer(128)
{
assert(_buf1 && _buf2);
setg(0, 0, 0);
setp(_buffer.data(), _buffer.data(), _buffer.data() + _buffer.size());
}
~StreambufDoubler() {
sync();
}
void imbue(const std::locale& loc) {
_buf1->pubimbue(loc);
_buf2->pubimbue(loc);
}
std::streampos seekpos(std::streampos sp, std::ios_base::openmode which) {
return seekoff(sp, std::ios_base::cur, which);
}
std::streampos seekoff(std::streamoff off, std::ios_base::seekdir way, std::ios_base::openmode which) {
if (which | std::ios_base::in)
throw(std::runtime_error("Can't use this class to read data"));
// which one to return? good question
// anyway seekpos and seekoff should never be called
_buf1->pubseekoff(off, way, which);
return _buf2->pubseekoff(off, way, which);
}
int overflow(int c) {
int retValue = sync() ? EOF : 0;
sputc(c);
return retValue;
}
int sync() {
_buf1->sputn(pbase(), pptr() - pbase());
_buf2->sputn(pbase(), pptr() - pbase());
setp(_buffer.data(), _buffer.data(), _buffer.data() + _buffer.size());
return _buf1->pubsync() | _buf2->pubsync();
}
private:
std::streambuf* _buf1;
std::streambuf* _buf2;
std::vector<char> _buffer;
};
int main() {
std::ofstream myFile("file.txt");
StreambufDoubler doubler(std::cout.rdbuf(), myFile.rdbuf());
std::cout.rdbuf(&doubler);
// your code here
return 0;
}
However note that a better implementation would use templates, a list of streambufs instead of just two, etc. but I wanted to keep it as simple as possible.

What you want actually is to follow in real time the lines added to the log your application writes.
In the Unix world, there's a simple tool that has that very function, it's called tail.
Call tail -f your_file and you will see the file contents appearing in almost real time in the console.
Unfortunately, tail is not a standard tool in Windows (which I suppose you're using, according to your question's tags).
It can however be found in the GnuWin32 package, as well as MSYS.
There are also several native tools for Windows with the same functionality, I'm personally using Tail For Win32, which is licensed under the GPL.
So, to conclude, I think your program should not output the same data to different streams, as it might slow it down without real benefits, while there are established tools that have been designed specifically to solve that problem, without the need to develop anything.

i don't program in c++ but here is my advice: create new class, that takes InputStream (istream in c++ or smth), and than every incoming byte it will transfer in std.out and in file.
I am sure there is a way to change standard output stream with forementioned class. As i remember, std.out is some kind of property of cout.
And again, i spent 1 week on c++ more than half a year ago, so there is a chance that all i've said is garbage.

Related

I can't get the ofstream function to work

Hello and sorry if the answer is clear to those out there. I am still fairly new to programming and ask for some guidance.
This function should write just one of the three string parameters it takes in to the txt file I have already generated. When I run the program the function seems to work fine and the cout statement shows the info is in the string and does get passes successfully. The issue is after running the program I go to check the txt file and find it is still blank.
I am using C++17 on visual studio professional 2015.
void AddNewMagicItem(const std::string & ItemKey,
const std::string & ItemDescription,
const std::string &filename)
{
const char* ItemKeyName = ItemKey.c_str();
const char* ItemDescriptionBody = ItemDescription.c_str();
const char* FileToAddItemTo = filename.c_str();
std::ofstream AddingItem(FileToAddItemTo);
std::ifstream FileCheck(FileToAddItemTo);
AddingItem.open(FileToAddItemTo, std::ios::out | std::ios::app);
if (_access(FileToAddItemTo, 0) == 0)
{
if (FileCheck.is_open())
{
AddingItem << ItemKey;
std::cout << ItemKey << std::endl;
}
}
AddingItem.close(); // not sure these are necessary
FileCheck.close(); //not sure these are necessary
}
This should print out a message onto a .txt file when you pass a string into the ItemKey parameter.
Thank you very much for your help and again please forgive me as I am also new to stackoverflow and might have made some mistakes in formatting this question or not being clear enough.
ADD ON: Thank you everyone who has answered this question and for all your help. I appreciate the help and would like to personally thank you all for your help, comments, and input on this topic. May your code compile every time and may your code reviews always be commented.
As mentioned by previous commenters/answerers, your code can be simplified by letting the destructor of the ofstream object close the file for you, and by refraining from using the c_str() conversion function.
This code seems to do what you wanted, on GCC v8 at least:
#include <string>
#include <fstream>
#include <iostream>
void AddNewMagicItem(const std::string& ItemKey,
const std::string& ItemDescription,
const std::string& fileName)
{
std::ofstream AddingItem{fileName, std::ios::app};
if (AddingItem) { // if file successfully opened
AddingItem << ItemKey;
std::cout << ItemKey << std::endl;
}
else {
std::cerr << "Could not open file " << fileName << std::endl;
}
// implicit close of AddingItem file handle here
}
int main(int argc, char* argv[])
{
std::string outputFileName{"foobar.txt"};
std::string desc{"Description"};
// use implicit conversion of "key*" C strings to std::string objects:
AddNewMagicItem("key1", desc, outputFileName);
AddNewMagicItem("key2", desc, outputFileName);
AddNewMagicItem("key3", desc, outputFileName);
return 0;
}
Main Problem
std::ofstream AddingItem(FileToAddItemTo);
opened the file. Opening it again with
AddingItem.open(FileToAddItemTo, std::ios::out | std::ios::app);
caused the stream to fail.
Solution
Move the open modes into the constructor (std::ofstream AddingItem(FileToAddItemTo, std::ios::app);) and remove the manual open.
Note that only the app open mode is needed. ofstream implies the out mode is already set.
Note: If the user does not have access to the file, the file cannot be opened. There is no need to test for this separately. I find testing for an open file followed by a call to perror or a similar target-specific call to provide details on the cause of the failure to be a useful feature.
Note that there are several different states the stream could be in and is_open is sort of off to the side. You want to check all of them to make sure an IO transaction succeeded. In this case the file is open, so if is_open is all you check, you miss the failbit. A common related bug when reading is only testing for EOF and winding up in a loop of failed reads that will never reach the end of the file (or reading past the end of the file by checking too soon).
AddingItem << ItemKey;
becomes
if (!(AddingItem << ItemKey))
{
//handle failure
}
Sometimes you will need better granularity to determine exactly what happened in order to properly handle the error. Check the state bits and possibly perror and target-specific
diagnostics as above.
Side Problem
Opening a file for simultaneous read and write with multiple fstreams is not recommended. The different streams will provide different buffered views of the same file resulting in instability.
Attempting to read and write the same file through a single ostream can be done, but it is exceptionally difficult to get right. The standard rule of thumb is read the file into memory and close the file, edit the memory, and the open the file, write the memory, close the file. Keep the in-memory copy of the file if possible so that you do not have to reread the file.
If you need to be certain a file was written correctly, write the file and then read it back, parse it, and verify that the information is correct. While verifying, do not allow the file to be written again. Don't try to multithread this.
Details
Here's a little example to show what went wrong and where.
#include <iostream>
#include <fstream>
int main()
{
std::ofstream AddingItem("test");
if (AddingItem.is_open()) // test file is open
{
std::cout << "open";
}
if (AddingItem) // test stream is writable
{
std::cout << " and writable\n";
}
else
{
std::cout << " and NOT writable\n";
}
AddingItem.open("test", std::ios::app);
if (AddingItem.is_open())
{
std::cout << "open";
}
if (AddingItem)
{
std::cout << " and writable\n";
}
else
{
std::cout << " and NOT writable\n";
}
}
Assuming the working directory is valid and the user has permissions to write to test, we will see that the program output is
open and writable
open and NOT writable
This shows that
std::ofstream AddingItem("test");
opened the file and that
AddingItem.open("test", std::ios::app);
left the file open, but put the stream in a non-writable error state to force you to deal with the potential logic error of trying to have two files open in the same stream at the same time. Basically it's saying, "I'm sorry Dave, I'm afraid I can't do that." without Undefined Behaviour or the full Hal 9000 bloodbath.
Unfortunately to get this message, you have to look at the correct error bits. In this case I looked at all of them with if (AddingItem).
As a complement of the already given question comments:
If you want to write data into a file, I do not understand why you have used a std::ifstream. Only std::ofstream is needed.
You can write data into a file this way:
const std::string file_path("../tmp_test/file_test.txt"); // path to the file
std::string content_to_write("Something\n"); // content to be written in the file
std::ofstream file_s(file_path, std::ios::app); // construct and open the ostream in appending mode
if(file_s) // if the stream is successfully open
{
file_s << content_to_write; // write data
file_s.close(); // close the file (or you can also let the file_s destructor do it for you at the end of the block)
}
else
std::cout << "Fail to open: " << file_path << std::endl; // write an error message
As you said being quite new to programming, I have explicitly commented each line to make it more understandable.
I hope it helps.
EDIT:
For more explanation, you tried to open the file 3 times (twice in writing mode and once in reading mode). This is the cause of your problems. You only need to open the file once in writing mode.
Morever, checking that the input stream is open will not tell you if the output stream is open too. Keep in mind that you open a file stream. If you want to check if it is properly open, you have to check it over the related object, not over another one.

Blocking read from std::ifstream

I am reading from a pipe (Linux) or a pipe-like device object (Windows) using std::ifstream::read. However, when there is no more data, read reads 0 bytes and sets EOF. Is there a way to make a blocking read from an ifstream, such that it only returns when there is some more data?
I'd rather not busy wait for the EOF flag to clear.
If it is not possible with the C++ standard library, what is the closest other option? Can I do it in plain C, or do I have to resort to operating system specific APIs?
Unfortunately, std is very poor on any non-algorithmic functionality, like IO. You always have to rely on 3rd-party solutions. Fortunately, there is Boost and, if you do not mind, I will suggest to use it to reduce OS specific code.
namespace bs = boost::iostreams;
int fd; // Create, for example, Posix file descriptor and specify necessary flags for it.
bs::file_descriptor_source fds(fd);
bs::stream<bs::file_descriptor_source> stream(fds);
// Work with the stream as it is std stream
In this small example I use Boost IO Streams and specifically file_descriptor_source that works as an underlying stream device and hides Windows or Posix specific pipe inside. The pipe you open yourself, so you can configure the pipe as you want.
well there seems no way to do a blocking read. clearing the error bit will not help. Only a re-open of the fifo like in this example:
int main(int argc, char **argv)
{
int rc=0;
enum FATAL {ERR_ARGV,ERR_OPEN_FILE};
try
{
if( argv[1] == NULL) throw ERR_ARGV;
std::ifstream fifo;
while(1)
{
fifo.open(argv[1],std::ifstream::in);
if( !fifo.is_open() ) throw ERR_OPEN_FILE;
std::string line;
while(std::getline(fifo,line))
{
std::cout << line << "\n"; fflush(stdout);
}
fifo.close();
}
// never should come here
}
catch(FATAL e)
{
rc=e;
switch(e)
{
case ERR_ARGV:
std::cerr << "ERROR: argument 1 should be a fifo file name\n";
break;
case ERR_OPEN_FILE:
std::cerr << "ERROR: unabel to open file " << argv[1] << "\n";
break;
}
}
return(rc);
}
I have tested this code and it works to do an endless read from a fifo.

How to enter to and read from a console program?

For a program that I want to write, I have to enter commands to and read from a console program, and I have no idea how to.
For understanding, perhaps a solution to the following example would be helpful:
I want to write a program that squares all natural numbers up to 100 and saves the result to a text file. Assume that I don't know how to square numbers and therefore use the executable file square_x.exe with the following (unavailable) source code:
#include <iostream>
using namespace std;
int main(){
double in;
cout << "Input: ";
while(cin>>in){
cout << in << static_cast<char>(253)/*²*/ << " = " << in*in << endl
<< endl
<< "Input: ";
}
return 0;
}
How then must I add to the following code fragment? (Proposedly, where indicated by "Somehow"):
#include <fstream>
using namespace std;
ofstream file;
void writeToFile( const char* name, const char* content ){
file.open( name, ios::app );
file << content;
file.close();
}
int main(){
char buffer[30], buffer2[50];
//Somehow call square_x.exe
for( int i = 1 ; i <= 100 ; i++ ){
//Somehow send i to square_x.exe
//Somehow get a result from square_x.exe and safe it to buffer2
//Extract from the got string the result of the calculation
strtok(buffer2," "); strtok(0, " ");
strncpy(buffer2,strtok(0, " \n"),sizeof(buffer2)-1);
sprintf( buffer , "%d\n%s\n\n" , i , buffer2 );
writeToFile( "list.txt", buffer );
}
//Somehow close square_x.exe
return 0;
}
I asked a friend of mine if he could help me with that and he sent me this. But since I have no idea how I would have to change this code to fulfill my needs, he then sent me here.
I assume that want you really want is the way to pass input to an auxilliary program and get its output.
The referenced link explains how to do it using WinAPI functions. Unfortunately, there is no simpler solution on Windows, because of the lacking of a fork function(*).
Taking the link as reference you must replace in your source //Somehow call square_x.exe with pipes and child process creation (CreatePipeand CreateProcess API calls, child process here is square_x.exe). Then to send something to the child, you just use WriteFile on the write end of the input pipe, and to read from the child, you use ReadFile from the read end of the output pipe.
But you example will be a little harder, because you child adds the noisy string "Input: " that you will have to ignore.
Try to put this in your code, and come back here to ask another question (with the new code) if you are stuck.
(*) But you could find a library that deals with all that gory details for you, such as libexecstream proposed by #a486408.
You can try using libexecstream - it allows you to launch new processes and communicate with them using c++ iostreams without digging into OS-specific stuff.

How to open a process and read the results into an ifstream from within a C++ program?

I am writing a C++11 program that will run in a Unix environment (portability isn't a concern). Currently, I have a Makefile that invokes two processes, one which writes to a file and the second which reads from that file.
target:
mkfifo myfile
other_program > myfile &
my_program myfile
For various reasons, I want invoke all of this from within my_program. It looks like popen is promising, as it invokes an external process and provides a FILE* I can read. However, the existing file processing code I've already written uses ifstream:
std::ifstream stream1(argv[1]);
Is there a decent way to connect popen's FILE* to an ifstream? Is there something else I should use instead of popen?
You can create a stream buffer which reads from a FILE*. Clearly, you may need to change your code to use std::istream in case you use std::ifstream in other places than creating the stream but this should be a straight forward change. Here is a simple demo showing how to create a corresponding stream buffer and how to use it:
#include <cstdio>
#include <iostream>
struct FILEbuf
: std::streambuf {
FILEbuf(FILE* fp): fp_(fp) {}
int underflow() {
if (this->gptr() == this->egptr()) {
int size = fread(this->buffer_, 1, int(s_size), this->fp_);
if (0 < size) {
this->setg(this->buffer_, this->buffer_, this->buffer_ + size);
}
}
return this->gptr() == this->egptr()
? traits_type::eof()
: traits_type::to_int_type(*gptr());
}
FILE* fp_;
enum { s_size = 1024 };
char buffer_[s_size];
};
int main()
{
FILEbuf sbuf(popen("ls -l", "r"));
std::istream in(&sbuf);
for (std::string line; std::getline(in, line); ) {
std::cout << line << '\n';
}
}
In the past I have been told off for using popen() or system() because these calls are considered to be unsafe: both of these calls spawn a shell which can be used to hijack their behavior. The alternative is to create a stream buffer using file descriptors and using pipe(), dup() (or one of its siblings), close(), fork(), and execl() (or one of its siblings) to build the pipe directly.

Is my fstream bad or not good()?

So I have a .cpp file with a Function which recieves a filename, and should return a String with the contents of the file (actualy modified contents, I modified the code to make it more understandable, but that doesn't have any effect on my problem). The problem is that f.good() is returning false and the loop, which reads the file is not working.
CODE :
#include "StdAfx.h"
#include "Form21.h"
#include <string>
#include <fstream>
#include <iostream>
string ReadAndWrite(char* a){
char filename[8];
strcpy_s(filename,a);
string output;
char c;
ifstream f(filename,ios::in);
output+= "Example text"; // <-- this writes and returns just fine!
c = f.get();
while (f.good())
{
output+= c;
c= f.get();
}
return output;
}
Does anyone have an idea on why this is happening?
Does it have something to do with, that this is a seperate .cpp file( it doesnt even throw out an error when I remove #include <fstream>).
Maybe there is a different kind of method to make the loop?
I'll be very happy to hear any suggestions on how to fix this or maybe a different method on how to achieve my goal.
First, there's really no reason to copy the file name you receive -- you can just use it as-is. Second, almost any loop of the form while (stream.good()), while (!stream.bad()), while (stream), etc., is nearly certain to be buggy. What you normally want to do is check whether reading some data worked.
Alternatively, you can skip using a loop at all. There are a couple of ways to do this. One that works nicely for shorter files looks like this:
string readfile(std::string const &filename) {
std::ifstream f(filename.c_str());
std::string retval;
retval << f.rdbuf();
return retval;
}
That works nicely up to a few tens of kilobytes (or so) of data, but starts to slow down on larger files. In such a case, you usually want to use ifstream::read to get the data, something along this general line:
std::string readfile(std::string const &filename) {
std::ifstream f(filename.c_str());
f.seekg(0, std::ios_base::end);
size_t size = f.tellg();
std::string retval(size, ' ');
f.seekg(0);
f.read(&retval[0], size);
return retval;
}
Edit: If you need to process the individual characters (not just read them) you have a couple of choices. One is to separate it into phases, where you read all the data in one phase, and do the processing in a separate phase. Another possibility (if you just need to look at individual characters during processing) is to use something like std::transform to read data, do the processing, and put the output into a string:
struct character_processor {
char operator()(char input) {
// do some sort of processing on each character:
return ~input;
}
};
std::transform(std::istream_iterator<char>(f),
std::istream_iterator<char>(),
std::back_inserter(result),
character_processor());
I would check that strlen(a) is not greater than 7...
You might overrun filename and get a file name that doesn't exist.
Not relating the problem, I would re-write the function:
string ReadAndWrite(string a) { // string here, if you are into C++ already
string filename; // also here
filename = a; // simpler
string output;
char c;
ifstream f(filename.c_str()); // no need for ios::in (but needs a char *, not a string
output+= "Example text"; // <-- this writes and returns just fine!
f >> c; // instead c = f.get();
while (f) // no need for f.good())
{
output+= c;
f >> c; // again, instead c= f.get();
}
return output;
}
Might I suggest using fopen? http://www.cplusplus.com/reference/clibrary/cstdio/fopen/ It takes in a filename and returns a file pointer. With that you can use fgets to read the file line by line http://www.cplusplus.com/reference/clibrary/cstdio/fgets/