I have my class which has to have ifstream file in it.
I dont know how to present it in the class header
A:
class MyClass
{
...
ifstream file;
...
}
B:
class MyClass
{
...
ifstream& file;
...
}
I know that ifstream has to get path in the decaleration, so how do I do it?
Also how do I open a file with it?
EDIT:
I want the first way, but how do I use it SYNTAX-ly?
let's say this is the header(part of it)
class MyClass
{
string path;
ifstream file;
public:
MyClass();
void read_from_file();
bool is_file_open();
...
}
funcs
void MyClass::read_from_file()
{
//what do I do to open it???
this->file.open(this->path); //Maybe, IDK
... // ?
}
You more than likely want the first option. The second is a reference to some other ifstream object, rather than an ifstream that belongs to MyClass.
You don't need to give an ifstream a path immediately. You can later call the ifstream's open function and give that a path. However, if you want to open the ifstream immediately on initialisation, you need to use the constructor's initialisation list:
MyClass() : file("filename") { }
If you need the constructor to take the file name, simply do:
MyClass(std::string filename) : file(filename) { }
Initialise it in the constructor:
class my_class {
public:
my_class(char const* path) : file(path) {
}
my_class(std::string const& path) : my_class(path.c_str()) {
}
private:
std::ifstream file;
};
Also see The Definitive C++ Book Guide and List.
Related
I have two classes, Lexer and InputStream. In my main function, I create an instance of Lexer, passing in the string 'filename'. My intention is for Lexer to pass 'filename' into its member variable 'is', so that InputStream::getChar() can read out the characters when Lexer::getString() calls it. I'm not sure how to make this happen, because currently, filename is passed into Lexer just fine, but isn't passed into the constructor of InputStream. How can I get filename into InputStream's constructor?
class InputStream
{
public:
InputStream(string filename)
{
in.open(filename);
}
char getChar()
{
return in.get();
}
char nextChar()
{
return in.peek();
}
private:
ifstream in;
};
class Lexer
{
public:
Lexer(string filename)
{
this->filename = filename;
}
string getString()
{
while (is.nextChar() != EOF)
{
valueSoFar.push_back(is.getChar());
}
}
private:
string valueSoFar;
string filename;
InputStream is{filename};
};
Thanks for your help!
You can initialize Inputstream instance like below within Lexer Class Constructor
class Lexer
{
public:
Lexer(string filename)
: is(filename)
{
this->filename = filename;
}
string getString()
{
valueSoFar.push_back(is.getChar());
}
private:
string valueSoFar;
string filename;
InputStream is;
};
I am trying to use C++11 feature of class member initializer to initialize variables of class. The variables of class that I have are std::string and std::ifstream.
class A{
std::string filename = "f1.txt";
std::ifstream filestream = ....
public:
....
};
Is there any way to initialize filestream and also check for error at the same time using class member initialization.
What I want to do is, something similar to below :
class A{
std::string filename = "f1.txt";
std::ifstream filestream(filename);
if(filestream.is_open()) .... // check if file cannot be opened
public:
....
};
You can write and call an inline lambda-expression that performs the appropriate checks; such a lambda-expression has access to the data members:
class A {
std::string filename = "f1.txt";
std::ifstream filestream = [&] {
std::ifstream fs{filename};
if (!fs)
throw std::runtime_error("failed to open ifstream");
return fs;
}();
};
It may be clearer to separate out the logic into a reusable helper function taking filename as a parameter, e.g. a static member function:
class A {
std::string filename = "f1.txt";
std::ifstream filestream = openChecked(filename);
static std::ifstream openChecked(std::string const& filename)
{
std::ifstream fs{filename};
if (!fs)
throw std::runtime_error("failed to open ifstream");
return fs;
}
};
I need to know if there exists a method in ifstream so I can get the name of the file tied to it.
For instance
void some_function(ifstream& fin) {
// here I need get name of file
}
Is there a method in ifstream/ofstream that allows to get that?
As mentioned there's no such method provided by std::fstream and it's derivates. Also std::basic_filebuf doesn't provide such feature.
For simplification I'm using std::fstream instead of std::ifstream/std::ofstream in the following code samples
I would recommend, to manage the underlying file name in a little helper class yourself:
class MyFstream {
public:
MyFstream(const std::string& filename)
: filename_(filename), fs_(filename) {
}
std::fstream& fs() { return fs_; }
const std::string& filename() const { return filename_; }
private:
std::string filename_;
std::fstream fs_;
};
void some_function(MyFstream& fin) {
// here I need get name of file
std::string filename = fin.filename();
}
int main() {
MyFstream fs("MyTextFile.txt");
some_function(fs):
}
Another alternative,- if you can't use another class to pass to some_function() as mentioned above -, may be to use an associative map of fstream* pointers and their associated filenames:
class FileMgr {
public:
std::unique_ptr<std::fstream> createFstream(const std::string& filename) {
std::unique_ptr<std::fstream> newStream(new std::fstream(filename));
fstreamToFilenameMap[newStream.get()] = filename;
return newStream;
}
std::string getFilename(std::fstream* fs) const {
FstreamToFilenameMap::const_iterator found =
fstreamToFilenameMap.find(fs);
if(found != fstreamToFilenameMap.end()) {
return (*found).second;
}
return "";
}
private:
typedef std::map<std::fstream*,std::string> FstreamToFilenameMap;
FstreamToFilenameMap fstreamToFilenameMap;
};
FileMgr fileMgr; // Global instance or singleton
void some_function(std::fstream& fin) {
std::string filename = fileMgr.getFilename(&fin);
}
int main() {
std::unique_ptr<std::fstream> fs = fileMgr.createFstream("MyFile.txt");
some_function(*(fs.get()));
}
No. C++ streams do not save the name or the path of the file.
but, since you need some string to initialize the stream anyway, you can just save it for future use.
No, such a method does not exist.
I'm trying to make a wrapper for a file - so a small wrapper to fstream. I am in the process of making something that will want to read/write binary and text to file, so I can make model loaders talk in the same way.
I've one question: Why doesn't my file open when I call with this in ObjLoader.cpp ?
Scatterbrain::Log *_file = new Scatterbrain::Log( path, false, true );
if( ! _file->Works() )
std::cout << "Error!!";
Having this in scatterbrain.h ? I'm sure I've included the necessary headers as everything compiles fine, so I figure it must be a semantic problem with the way I wrote the file open call? - it is getting called..
namespace Scatterbrain
{
class Log
{
private:
std::string name;
bool rOnly;
bool isBinary;
int numBytes;
std::fstream file;
protected:
virtual int SizeBytes() { numBytes = (file) ? (int) file->tellg() : 0; return numBytes; }
public:
Log(){}
Log( std::string filename, bool append, bool readOnly )
{
if(FileExists(filename))
{
name = filename;
rOnly = readOnly;
file.open( name.c_str(), ((readOnly) ? int(std::ios::out) : int(std::ios::in |std::ios::out)) | ((append) ? int(std::ios::app) : int(std::ios::trunc)) );
}
}
virtual bool Works() { return (file.is_open() && file.good() ); }
Thanks
There's a lot that could be said about this all, so I'll just put it in comments:
class Log
{
private:
std::string name;
bool rOnly;
std::fstream file;
public:
Log(){}
Log( std::string filename, bool append, bool readOnly)
: name(filename), // Use initializer lists
rOnly(readOnly),
file(filename, (readOnly ? std::ios::out : std::ios::in | std::ios::out) |
(append ? std::ios::app : std::ios::trunc))
{
// Why check if the file exists? Just try to open it...
// Unless, of course, you want to prevent people from creating
// new log files.
}
virtual bool Works()
{
// Just use the fstream's operator bool() to check if it's good
return file;
}
};
In short:
Use member initializer lists
Don't use new... I have no idea why you were in the first place, or why it compiled if it did.
Use the operator bool() function to see if it's "good" or not.
I'm just wondering if it is possible to write in a dynamic array object which consist of virtual function, display() to a text file (eg. txtfiletodisplay.txt).
edited:
instead of using vector, im implementing it this way.
in main()
clsStaff** objStaff = new clsStaff[userInput];
ofstream outputFile("staff.txt");
for (x=0; x<userInput; x++)
outputFile = objStaff[x]->display();
class FileDisplayer
{
public:
virtual File display() const;
...
};
class File
{
...
};
std::vector<FileDisplayer*> objStaff; // this
FileDisplayer* objStaff[100]; // ... or this
FileDisplayer** objStaff; // ... or this
File outputFile = objStaff[x]->display();
No idea what you really mean, so FileDisplayer and File might be misleading names.
EDIT:
It might be that display is meant to take outputFile as a parameter (and outputFile is an output stream). In that case the above should be rewritten like this
class FileDisplayer
{
public:
virtual void display(std::ostream& file) const;
...
};
std::vector<FileDisplayer*> objStaff; // this
FileDisplayer* objStaff[100]; // ... or this
FileDisplayer** objStaff; // ... or this
std::ofstream outputFile;
...
objStaff[x]->display(outputFile);