C++ how to write a ifstream for multiple files? - c++

So I have several files that form a contingent number of lines, so let's call them file1, file2, file3 and so forth. What I want to do is to create a istream class which streams all the files as if they were one. One thing i got is not to subclass std::istream but to reimplement streambuf. My question is: how would I go about this - how would i be able to read from multiple files without having them all in memory?

Is it possible to make an istream that reads multiple files?
Yes, but you'll have to make it yourself. You can implement your own istream class by extending std::istream, and then implementing the methods it defines:
class custom_istream : public std::istream {
std::ifstream underlying;
//... implement methods
};
The interface of std::istream is sufficiently flexible to allow you to do what you want. However, implementing std::istream would require a lot of work, as you'd have to implement the entirety of the interface.
Is there an easier solution?
If you only need a subset of the functionality provided by std::istream, you could just write your own class.
For example, if you only need to be able to read lines from the file, the below class will work just fine for multiple files:
class MultiFileReader {
std::ifstream filestream;
std::ios_base::openmode mode;
size_t file_index = 0;
std::vector<std::string> filenames;
void open_next_file() {
file_index++;
filestream = std::ifstream(filenames.at(file_index), mode);
}
public:
MultiFileReader(std::vector<std::string> const& files, std::ios_base::openmode mode)
: filestream(files[0], mode), mode(mode) {}
// Checks if there's no more files to open, and no more to read
// in the current file
bool hasMoreToRead() {
if(file_index == filenames.size()) return false;
if(file_index + 1 == filenames.size())
return not filestream.eof();
return true;
}
std::string read_line() {
if(not hasMoreToRead()) {
throw std::logic_error("No more to read");
}
// If at the end of the file, open the next file
if(filestream.eof()) {
open_next_file();
}
else {
std::string line;
std::getline(filestream, line);
return line;
}
}
};

Related

Moving std::istream

I have a Scanner class to tokenize streams of characters coming from files, cin, etc.
class Scanner {
public:
Scanner(std::istream&& c) : input{std::move(c)} {}
private:
std::istream input;
};
This code does not compile because the move constructor of std::istream is protected. I could use a reference to the stream instead, but then, I have no guarantee that someone is not playing with my stream outside of the Scanner class (ss below).
std::string code = "this is code";
std::stringstream ss{code};
Scanner scanner{ss};
Is there a neat way to address this issue, or do people just use std::istream& and hope for the best?
From what I can remember about my work with stream objects.
You need to think about this a bit differently.
class Scanner {
public:
Scanner() {}
virtual void scan(std::istream & p_stream);
};
Your Scanner class could just be focused on scanning the input for whatever, not actually containing it.
Now it can be focused purely on a single task.
Then you need to work out what is the best way for you to keep the stream object alive. I suggest a separate class for that task.
I would have written this as a comment, but there's too much here.

ofstream inside array writes to same file all the time

I've a structure like in below:
std::list -> Includes list of objects in type of VolataliteAnalyzer *(Which is my custom class) -> VolataliteAnalyzer object keeps a ofstream object as in below code. And I'm calling the below method to write appropriate files
void VolataliteAnalyzer::writeToFile (unsigned long orderBookId,double volatalite,double currentWarrantPrice,double stockPrice,double expireDate,double strikePrice)
{
logger.logMessage(new MessageInfoLog(std::string(__PRETTY_FUNCTION__)+" Writing File For :"+std::to_string(orderBookId)));
if (!warrantFile.is_open()) {
std::string filePath = std::string(FILE_NAME)+std::string("_")+std::to_string(orderBookId)+std::string(FILE_EXT);
warrantFile.open (filePath,std::ios_base::app);
logger.logMessage(new MessageInfoLog(std::string(__PRETTY_FUNCTION__)+" Creating File:"+filePath));
}
warrantFile << this->getCurrentDate()+DELIMETER+std::to_string(volatalite)+DELIMETER+std::to_string(currentWarrantPrice)+DELIMETER+std::to_string(stockPrice)+DELIMETER+std::to_string(expireDate)+DELIMETER+std::to_string(strikePrice)+"\n";
}
However when I call this method , for different objects in the array , it always writes to same file . But instead it should write to unique files for each object in array. I've tested it many times but wasnt able to understand the reason. I suspected that if ofstream objects are singleton or something like that?
class VolataliteAnalyzer {
public:
double selectedVolatalite=0;
VolataliteAnalyzer();
void writeToFile(unsigned long orderBookId,double volatalite,double currentWarrantPrice,double stockPrice,double expireDate,double strikePrice);
void finishWriting();
bool loadFromFile(unsigned long orderBookId);
void getSelectedVolatalite(int dayCount);
private:
Logger& logger;
std::ofstream warrantFile;
std::ifstream warrantReader;
std::string getCurrentDate();
std::list<Volatalite *> dailyVolatalites;
Volatalite* getVolatalite(std::string date);
};

how to reuse class containing std::ifstream?

I have a class A which handles file by opening, reading and closing. I also have another class B that use A to read file. B has instance of A as private member data. I want to reuse the a and use it to read multiple files using this instance. I also read some where that we cannot copy any of the stream. So my question is how can I handle class A to read multiple files in B?
class A{
A(std::string s){
f.open(s);
}
void read_file(){
/// read file
// close after reading
f.close();
}
private:
std::ifstream f;
};
class B{
B(std::string s_):a(s_){}
void read_multiple_files(){
a.read_file();
// now lets read another file
a = A("another_file_1.txt");
a.read_file();
////////////////////
// now lets read another file
a = A("another_file_2.txt");
a.read_file();
}
private:
A a
};
This is probably a design issue. There seems no reason for B to hold an instance of A unless it needs to keep a file handle across different method calls.
Instead, simply create an A to read each file:
class B {
void read_multiple_files() {
// read our files
auto result = A("another_file_1.txt").read_file();
auto result_2 = A("another_file_2.txt").read_file();
...
}
}

Qt - How to save data for my application

I'm pretty new to Qt and I have a problem with finding out how to save/load data from your application.
I'm creating a Calendar app and have to save different classes like: Deathlines, appointments, birthdays, etc.
And I've found this tutorial http://qt-project.org/doc/qt-4.8/tutorials-addressbook-part6.html but it only describes how to save one type of class.
So I was wondering if you could help me, because I have no idea how to save/load multiple classes that way, I don't need some detailed description of it (however it would be appreciated of course) but only a gentle push into the right direction.
Because nowhere in this tutorial is explained how to save multiple classes :(
EDIT: This program is for PC (project for school)
You can define your custom class and implement stream operators for it :
class CustomType
{
public:
CustomType()
{
paramter1=0;
paramter2=0;
paramter3="";
}
~CustomType(){}
int paramter1;
double parameter2;
QString parameter3;
};
inline QDataStream& operator<<( QDataStream &out, const CustomType& t )
{
out<<t.paramter1;
out<<t.paramter2;
out<<t.paramter3;
return out;
}
inline QDataStream& operator>>( QDataStream &in, CustomType& t)
{
in>>t.paramter1;
in>>t.paramter2;
in>>t.paramter3;
return in;
}
You should register the stream operators of your class somewhere in your code when starting your application before streaming the class. This could be done in the constructor of your main window :
qRegisterMetaTypeStreamOperators<CustomType>("CustomType");
Now you can save or load objects of your class to or from file.
Saving some objects of your custom classes to a file :
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly)) {
QMessageBox::information(this, tr("Unable to open file"),
file.errorString());
return;
}
QDataStream out(&file);
out.setVersion(QDataStream::Qt_4_8);
out << object1;
out << object2;
loading objects of your custom classes from a file :
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
QMessageBox::information(this, tr("Unable to open file"),
file.errorString());
return;
}
QDataStream in(&file);
in.setVersion(QDataStream::Qt_4_8);
in >> object1;
in >> object2;
Note that the order of reading and writing to file should be the same.

C++ How to dynamically select a file handle according to the type of data that should be written?

I've got a class outputInterface; that should handle the output (to files) of some data. The data is contained in objects of some custom classes, say dataClassA and dataClassB, that all derive from a common base class dataClassBase.
Now I want the data to be written to different files according to its type. So data of type dataClassA should go to fileA, data of type dataClassB should go to fileB and so on. As this output happens very often I would like the file handles (fileA and fileB) to stay open, i.e. I don't want to open and close the files for the output of each piece of data. One outputInterface object can be expected to exist all the time.
So what I would like to achieve is something like this:
Dynamically associate data of type dataClassA with the file handle fileA etc.
When receiving data of type dataClassA check whether fileA is already connected to a file, if not, open the file.
How can I get this behavior (or least something similar / better)?
I've been thinking of making the file handles static members of dataClassA and dataClassB (or the base class dataClassBase?). But then, how do I take care of closing the files? I would have to somehow keep track of the data types that have actually been used (the files that have actually been opened).
Try something like this:
#ifndef OUTPUTINTERFACE?H
#define OUTPUTINTERFACE?H
#include <string>
#include <fstream>
#include <map>
class DataClass
{
public:
virtual bool WriteData(std::ofstream& FStream) = 0;
};
class DataClass1 :
public DataClass
{
virtual bool WriteData(std::ofstream& FStream)
{
FStream << "teletubbies";
}
};
class DataClass2 :
public DataClass
{
virtual bool WriteData(std::ofstream& FStream)
{
FStream << "garbage";
}
};
class OutputInterface
{
public:
OutputInterface()
{
}
~OutputInterface()
{
//Release stream pointers
}
template<typename T>
bool WriteData(T& Data)
{
std::string dClassUID = std::string(typeid(T).name);
tFStreamMap::iterator it this->streamMap.find(dClassUID);
std::ofstream* stream = NULL;
if(it != streamMap.end())
{
stream = it->second;
}
else
{
stream = new std::ofstream();
stream->open(dClassUID + ".txt");
streamMap.insert(std::make_pair(dClassUID, stream));
}
Data.WriteData(stream);
}
private:
typedef std::map<std::string, std::ofstream*> tFStreamMap;
tFStreamMap streamMap;
};
#endif
This is just a prove of concept and can be optimized in many ways.
I would rather stick with overloaded functions than with runtime type checks.
This is fairly easy to implement in C++11, using an
std::map<std::type_index, std::ostring*> outputMap. (In C++03, you'll have to
implement the equivalent of std::type_index yourself.) You get the
output stream using outputMap[typeid(*data)]. The only problem is
getting the streams into the map to begin with: you can do something
like:
std::ostream*& destPtr = outputMap[typeid(*data)];
if ( destPtr == NULL ) {
destPtr = new std::ofstream("...");
}
std::ostream& dest = *destPtr;
But from where do you get the filename?
There's also the question of when you close the streams: you can't
normally close an output stream in a destructor, since closing an output
stream is an operation which can fail, and you need to detect and react
to that failure. Probably with an exception, which is why you don't
want to do it in a destructor.
Since the "data" part comes from dataClassBase, you can make a virtual/pure-virtual function 'WriteData` in this class, and let derive class implement it.
The class outputInterface may take objects of type dataClassBase and would directly call WriteData. Other than WriteData you may also add other virtual functions in dataClassBase
You did not mention relationship between outputInterface and dataClassBase