Working with file streams generically - c++

I want to work with file streams generically. That is, i want to 'program to an interface and not the implementation'. Something like this:
ios * genericFileIO = new ifstream("src.txt");
getline(genericFileIO, someStringObject);//from the string library; dont want to use C strings
genericFileIO = new ofstream("dest.txt");
genericFileIO -> operator<<(someStringObject);
Is it possible? I am not great with inheritance. Given the io class hierarchy, how do i implement what i want?

Do you mean:
void
pass_a_line(std::istream& in, std::ostream& out)
{
// error handling left as an exercise
std::string line;
std::getline(in, line);
out << line;
}
This can work with anything that is an std::istream and std::ostream, like so:
// from a file to cout
// no need to new
std::ifstream in("src.txt");
pass_a_line(in, std::cout);
// from a stringstream to a file
std::istringstream stream("Hi");
std::ofstream out("dest.txt");
pass_a_line(stream, out);
This does what your example do, and is programmed against the std::istream and std::ostream interfaces. But that's not generic programming; that's object oriented programming.
Boost.Iostreams can adapt classes to std::[i|o|io]streams, and does this using generic programming.

You can use different specialisations of the ostream or istream concepts over the ostream or istream interface.
void Write(std::ostream& os, const std::string& s)
{
os << "Write: " << s;
}
std::string Read(std::istream& is)
{
std::string s;
is >> s;
return s;
}
int main()
{
Write(std::cout, "Hello World");
std::ofstream ofs("file.txt");
if (ofs.good())
Write(ofs, "Hello World");
std::stringstream ss;
Write(ss, "StringStream");
Write(std::cout, ss.str());
std::string s = Read(std::cin);
Write(std::cout, s);
return 0;
}

Related

string representing date and transform it

To format a string representing date received from other part some transform is required:
source:
std::string s = "20190510";
target:
std::string t = "05/10/2019";
One way is to copy char by char, is there an elegant way to do it beautiful and fast?
UPDATE: Sorry the transform should be from "yyyymmdd" to "mm/dd/yyyy".
Try insert:
int main() {
std::string s = "20190510";
s.insert(4, "/");
s.insert(7, "/");
std::cout << s << std::endl;
}
If you don't want to modify the string or copy it, then you are left with the option of formatting it only when needed. This can be accomplished with a small utility:
struct date_format {
std::string const& str;
date_format(std::string const& str) : str(str) {}
friend std::ostream& operator<< (std::ostream& os, date_format const& df) {
return os.write(&df.str[4], 2)
.put('/')
.write(&df.str[6], 2)
.put('/')
.write(&df.str[0], 4);
}
};
To be used like this for instance std::cout << date_format(source);, see it live.
Otherwise it's definitely going to entail copying or moving characters about.

Difficulty overloading operator<< for file handling class

I have to:
Define a File_handle class with constructor that takes a string argument (file name), opens the file in the constructor, and closes it in the destructor.
As I understand it, this class is used to provide RAII and I am trying to implement the class using FILE* as basic data structure where my goal basically is to make FILE* a smart pointer:
fileHandler.h:
// Class CFile_handler based on FILE*
class CFile_handler {
public:
CFile_handler(); // default constructor
CFile_handler(const std::string& fileName, // constructor
const std::string& mode);
~CFile_handler (); // destructor
// modifying member function
void open_file(const std::string& fileName,
const std::string& mode);
protected:
typedef FILE* ptr;
private:
CFile_handler(const CFile_handler&); // prevent copy creation
CFile_handler& operator= (const CFile_handler&); // prevent copy assignment
ptr c_style_stream; // data member
};
fileHandler.cpp:
// Class CFile_handler member implementations
// default constuctor
CFile_handler::CFile_handler() {
}
// constructor
CFile_handler::CFile_handler(const std::string& fileName, const std::string& mode = "r")
: c_style_stream( fopen( fileName.c_str(), mode.c_str() ) )
{
}
// destructor
CFile_handler::~CFile_handler() {
if (c_style_stream) fclose(c_style_stream);
}
// Modifying member functions
void CFile_handler::open_file(const std::string& fileName, const std::string& mode) {
c_style_stream = ( fopen( fileName.c_str(), mode.c_str() ) );
}
However, I'm having difficulties in overloading I/O operators<< / >>, as I can't figure out how to implement either of them.
How to overload operator<< such that the class works with iostream objects?
Edit:
As it was proposed by #LokiAstari, it would be better strategy to inherit from istream and define own streambuf.
Could someone give an example or directions for the implementation of streambuf that handles FILE*?
What I want to provide is:
CFile_handler fh("filename.txt", "r");
std::string file_text;
fh >> file_text;
or:
CFile_handler fh("filename.txt", "w");
fh << "write this to file";
You can derive types of the std::streams using std::streambuf to handle the FILE*
#include <iostream>
#include <stdio.h>
class OutputFilePointerStream: public std::ostream
{
class OutputFilePointerStreamBuf: public std::streambuf
{
FILE* buffer;
public:
OutputFilePointerStreamBuf(std::string const& fileName)
{
buffer = fopen(fileName.c_str(), "w");
}
~OutputFilePointerStreamBuf()
{
fclose(buffer);
}
virtual std::streamsize xsputn(const char* s, std::streamsize n) override
{
static char format[30];
sprintf(format, "%%.%lds", n);
fprintf(buffer, format, s);
return n;
}
};
OutputFilePointerStreamBuf buffer;
public:
OutputFilePointerStream(std::string const& fileName)
: std::ostream(nullptr)
, buffer(fileName)
{
rdbuf(&buffer);
}
};
int main()
{
OutputFilePointerStream fileStream("Test");
fileStream << "Testing: " << 5 << "><\n";
fileStream << "Line Again\n";
}
Your operator<< function is to output a CFile_handler object to a C++ output stream, it's not for outputting to a CFile_handler object.
To output to a CFile_handler object you have two choices:
As a member function
CFile_handler& CFile_handler::operator<<(int value)
{
// Output an integer to the contained file
return *this;
}
Or as a non-member function which takes a CFile_handler reference as first argument:
CFile_handler& operator<<(CFile_handler& file, int value)
{
// Output an integer to the file contained in `file`
return file;
}
For both of the above variants, you can then do e.g.
CFile_handler my_file(...);
my_file << 1234;

Overloading cout for logging purposes?

I would like to define something like a new cout, which I can use to log my data:
some_type cout2( Message_type message ){
cout << message;
logfile.save(message);
}
so I will use it with
cout2 << "some message" << endl;
Up to now I was not able to find out how the code above has to look like exactly.
Thanks for your help.
You can create your own logger like:
class Logger {
public:
Logger(std::string const& filename)
: stream_(filename, std::ofstream::out | std::ofstream::app)
{
if (!stream_) {
// Error...
}
}
Logger& operator<<(std::string const& str) {
std::cout << str;
stream_ << str;
return *this;
}
private:
std::ofstream stream_;
};
Generally speaking, classes from C++ standard library are not designed to be derived, and that is true for stream classes.
So IMHO, it is better to specify what method you will need on your cout2 object, and then:
design a class containing a ostream& object, initialized in ctor
delegate actual output to that internal object
do whatever log you need in your methods
You should use templated a operator << to be able to easily process any class that std::ostream can process.
class LogStream {
std::ostream& out;
Logfile logfile;
LogStream(std::ostream& out, /* param for logfile initialization */ ...)
: out(out), logfile(...) {}
... // other useful methods for state
};
template<typename T>
LogStream& operator << (LogStream& out, T val) {
out.out << message;
// should first test whether T is manipulator, and choose whether and how it should be logged
logfile.save(message);
}
You don't want to modify std::cout.
Instead, you want to create a specialised std::streambuf that writes to two buffers rather than one. For example;
#include <streambuf>
template <typename char_type,
typename traits = std::char_traits<char_type> >
class basic_teebuf:
public std::basic_streambuf<char_type, traits>
{
public:
typedef typename traits::int_type int_type;
basic_teebuf(std::basic_streambuf<char_type, traits> * sb1,
std::basic_streambuf<char_type, traits> * sb2)
: sb1(sb1)
, sb2(sb2)
{
}
protected: // override virtuals inherited from std::basic_streambuf
virtual int sync()
{
int const r1 = sb1->pubsync();
int const r2 = sb2->pubsync();
return r1 == 0 && r2 == 0 ? 0 : -1;
}
virtual int_type overflow(int_type c)
{
int_type const eof = traits::eof();
if (traits::eq_int_type(c, eof))
{
return traits::not_eof(c);
}
else
{
char_type const ch = traits::to_char_type(c);
int_type const r1 = sb1->sputc(ch);
int_type const r2 = sb2->sputc(ch);
return
traits::eq_int_type(r1, eof) ||
traits::eq_int_type(r2, eof) ? eof : c;
}
}
private:
std::basic_streambuf<char_type, traits> * sb1;
std::basic_streambuf<char_type, traits> * sb2;
};
typedef basic_teebuf<char> teebuf;
Then you need to create a specialised ostream which uses such a buffer
#include <ostream>
class teestream : public std::ostream
{
public:
// Construct an ostream which tees output to the supplied
// ostreams.
teestream(std::ostream & o1, std::ostream & o2);
private:
teebuf tbuf;
};
teestream::teestream(std::ostream & o1, std::ostream & o2)
: std::ostream(&tbuf)
, tbuf(o1.rdbuf(), o2.rdbuf())
{
}
All the above does is create a specialised std::ostream that uses our specialised buffer, which in turn makes use of two buffers.
Now, our teestream needs to be initialised using two streams. For example
#include <fstream>
#include <iostream>
// include the preceding definition of teestream here
int main()
{
std::ofstream logfile("hello-world.log");
teestream tee(std::cout, logfile);
// tee is now a stream that writes the same output to std::cout and logfile
tee << "Hello, world!\n";
return 0;
}
The advantage of this is that all stream insertions (operator <<) will work with our teestream - even for classes with overloaded versions.
When main() returns, the streams will also be closed cleanly.
I've written the specalised streambuf as a template (std::streambuf is a specialisation of a templated class named std::basic_streambuf). For generality, it would probably be better to do the same with the stream (using the fact that std::ostream is also a specialisation of a templated std::basic_ostream). I leave that sort of generalisation as an exercise.
The logging systems I've seen, built on this idea look something like this:
#define MY_PRINT(x, ...) \
{ \
fprintf(logFile, x, ##__VA_ARGS__); \
fflush(acuLogFile); \
}
And you would use it like:
MY_PRINT("this is just a test\n");
Even though this is the C way of doing things, it is very versatile and work in C++ as well.
You just have to use your newly define print function everywhere in the code.
Maybe you should have an instance based logger with a .log() method, that, depending on implementation can log to file, write to stdout etc, rather than trying to overload free functions from std namespace?
Your intent will be clearer and it will be more object orientated.
In fact here is an example of a pretty cookie-cutter event logger I wrote recently, if that helps you to understand the sort of thing I'm talking about. My design allows for dependnacy injection, as well as keeping boring decisions about how something should be formatted as output and where it should go (stdout or file etc) in the logger.
Of course you can define your own cout.
First you need a class which can handle the << operator and contains an fstream and an ostream (like cout).
class logstream
{
private:
fstream *filestream;
ostream *cout;
public:
logstream(fstream* filestream, ostream* cout)
{
this->cout = cout;
this->filestream = filestream;
}
string operator<< (char* s)
{
*cout << s;
*filestream << s;
return s;
}
};
To use this, simply initialize it with cout and a fstream.
fstream lout = fstream("Filename", ios::app);
logstream cout = logstream(&lout, &std::cout);
And now you have what you wanted.
cout << "message";
EDIT: Don't forget to include
#include <iostream>
#include <fstream>
and
using namespace std;

Extending C++ ostream

I'm trying to learn more about the workings of the C++ I/O stream library by extending std::streambuf. As a learning experiment, my goal is to simply create a custom stream which directs all output to std::cerr. It seems simple enough:
#include <iostream>
using namespace std;
class my_ostreambuf : public std::streambuf
{
public:
protected:
std::streamsize xsputn(const char * s, std::streamsize n)
{
std::cerr << "Redirecting to cerr: " << s << std::endl;
return n;
}
};
int main()
{
my_ostreambuf buf;
std::ostream os(&buf);
os << "TEST";
}
This seems to work, since it prints Redirecting to cerr: TEST. The problem is that it doesn't work when a single character (as opposed to a string) is inserted into the stream via std::ostream::sputc. For example:
int main()
{
my_ostreambuf buf;
std::ostream os(&buf);
os << "ABC"; // works
std::string s("TEST");
std::copy(s.begin(), s.end(), std::ostreambuf_iterator<char>(os)); // DOESN'T WORK
}
The problem I guess is that xsputn doesn't handle single character insertion. (I guess sputc doesn't call xsputn internally?) But, looking over the list of virtual protected functions in std::streambuf, I don't see any function I'm supposed to override that handles single character insertion.
So, how can I accomplish this?
Single-character output is handled by overflow. Here's how you might implement overflow in terms of xsputn if xsputn does the actual outputting:
int_type overflow(int_type c = traits_type::eof())
{
if (c == traits_type::eof())
return traits_type::eof();
else
{
char_type ch = traits_type::to_char_type(c);
return xsputn(&ch, 1) == 1 ? c : traits_type::eof();
}
}

Reverse part of a stream (between markers) using effectors or manipulators

Greetings!
I'd like to make small program what reverses part of a stream between markers using stream effectors and/or manipulators For example:
From this:
cout << "something" << revstream::start << "asdf" << 3.14 << revstream::end << "something";
To this:
something41.3fdsasomething
I'd like it to work not just on the standard cout and I'd like to embed them several times.
I'm new in c++ and my main problems are:
- I can't create a new stream to store what is inside the markers
- How to reverse the temp stream?
I tried so many things and I stuck here:
class revstream {
public:
static ostream& start(ostream &os) {
//do the reversing
return ???;
}
static ostream& end(ostream &os) {
return reversedstream;
}
};
You can do this, but it's ugly as butt:
class revstream: public std::ostream
{
public:
static std::ostream &start(std::ostream &os)
{
return *(new revstream(os));
}
static std::ostream &end(std::ostream &rev)
{
revstream *actual_rev= dynamic_cast<revstream *>(&rev);
// logic for reversing output goes here
std::ostream &result= actual_rev->os;
delete actual_rev;
return result;
}
revstream(std::ostream &in_os): std::ostream(&reversebuf), os(in_os)
{
return;
}
std::ostream &os;
std::stringbuf reversebuf;
};
Your ostream manipulator has to return a reference to ostream, so you have to allocate within revstream::start.
This isn't how you asked to go about it, but I would approach the problem in a different way. Instead of writing some kind of extension to the streams, why not just write a function that reverses a string?
#include <string>
#include <iostream>
using namespace std;
string reverse(const string& str)
{
return string(str.rbegin(), str.rend());
}
int main()
{
cout << reverse("asdf") << "\n";
}