Fstream Initialization in a Class - Checking if File Opened - c++

Example:
//Header File
class Example
{
private:
fstream InputObject;
public:
Example();
}
//Implementation File
Example::Example():InputObject("file_name.txt", ios::in) {}
From what I've read so far from similar questions, the only way, in the "older" version of C++, for initializing an fstream object in a class is to do so via member list initialization shown above.
Question:
If that really is the "only" way of initializing an fstream object in a class, what do we do if the file should fail to open?
Normally I'd run the fstream object through a check to make sure it opened properly, but this doesn't seem possible in this case. Also, even if I could, how could I reinitialize the object if it failed to do so the first time through?

#define WIN32_LEAN_AND_MEAN // This makes it so it doesn't look through libs that are not included when running
#include <fstream> //To Read write to files, to be able to
#include <iostream> // The basic stuff, cout, cin, etc.
using namespace std; // the capability of typing cout instead of std::cout
int main() // our main loop
{
fstream InputObject; // declaring InputObject as something that can write to a file
if(!Inputobject.open("File Name Here") // if it cant open the file
{
cout << "File not Open" << endl; // then write to console, " File not Open"
}
return 0;
system("pause");
}
You want to find out if the file is open, so using ! before the functio for opening file means , not open, so an if statement with !InputObject.open, will check if it is not open, if that is true, do something, so cout << "File is not open" will tell u if it is open or not.

From what I've read so far from similar questions, the only way, in the "older" version of C++, for initializing an fstream object in a class is to do so via member list initialization shown above.
That's not strictly true.
It is probably the preferred way of doing it. But you don't need to do it that way. And a failure simply sets the state to failed that can then be tested in the body of the constructor.
If that really is the "only" way of initializing an fstream object in a class
No.
what do we do if the file should fail to open?
Test and re-try in the body of the constructor.
Normally I'd run the fstream object through a check to make sure it opened properly, but this doesn't seem possible in this case. Also, even if I could, how could I reinitialize the object if it failed to do so the first time through?
There are standard API to reset the state of a stream after a failure.
Example::Example()
:InputObject("file_name.txt", std::ios::in)
{
if (!InputObject) {
InputObject.clear();
InputObject.open("AlternativeFile", std::ios::in)
}
}

Related

std::cout, ostream and other kinds of getting output stream

In my project (Unreal Engine 4) I don't have an output stream - instead of this I can communicate via UE_LOG function, which works pretty much similar to printf(). The problem is that I just made a .dll library (without Unreal includes) which I want to communicate through the iostream. My idea is - inside .dll library I use standard cout to write messages into ostream, I use all of it in Unreal Engine functions, where I grab ostream in form of string and output it into UE_LOG function.
Problem is I always treated std::cout as a part of magic, without thinking what is really inside (I am pretty sure most of us did). How I can handle this? Easy ways won't work (like grabbing stringstream and outputing it into UE_LOG).
My idea is - inside .dll library I use standard cout to write messages into ostream
You actually can replace the output buffer used with std::cout with your own implementation. Use the std::ostream::rdbuf() function to do so (example from the reference docs):
#include <iostream>
#include <sstream>
int main()
{
std::ostringstream local;
auto cout_buff = std::cout.rdbuf(); // save pointer to std::cout buffer
std::cout.rdbuf(local.rdbuf()); // substitute internal std::cout buffer with
// buffer of 'local' object
// now std::cout work with 'local' buffer
// you don't see this message
std::cout << "some message";
// go back to old buffer
std::cout.rdbuf(cout_buff);
// you will see this message
std::cout << "back to default buffer\n";
// print 'local' content
std::cout << "local content: " << local.str() << "\n";
}
(in case my edit won't be positively reviewed)
From OP: Thanks to your hints I finally found how to solve my problem. Suppose I want to get stream from cout and send it to printf (because I think stdio library is superior to iostream). Here how I can do this:
#include <iostream>
#include <sstream>
#include <cstdio>
using namespace std;
class ssbuf : public stringbuf{
protected:
int sync(){
printf("My buffer: %s",this->str().c_str());
str("");
return this->stringbuf::sync();
}
};
int main(){
ssbuf *buf = new ssbuf();
cout.rdbuf(buf);
cout<<"This is out stream "<<"and you cant do anything about it"<<endl;
cout<<"(don't) "<<"Vote Trump"<<endl;
}
Code is very raw, but it does it's job. I made child class of buffer which has method sync() downcasting original virtual method sync(). Except this it works like usual buffer, just grabs all console-out stream - exactly what we wanted. The str("") inside is to clean the buffer - probably not outputted stream doesn't clean itself.
Great thanks for help! Big GRIN for you! :D

C++ create ifstream/ofstream in a class, associated with pre-made text file

I am having a problem associating an ifstream read and ofstream print to a pre-made text file called finances.txt. This is within a class called Data. So far, this is what I've tried:
I declared ifstream read and ofstream print in the class header file. Then, in the cpp file:
Data::Data(string n, string d)
:name(n),
date(d)
read(name)
print(name)
{
cout << "name = " << name << endl;
read.open(name);
print.open(name);
//...
}
I also tried this, without declaring anything in the header:
Data::Data(string n, string d)
:name(n),
date(d)
{
ifstream read(name);
ofstream print(name);
//...
And just different variations of this kind of thing. The syntax is always correct in the sense that I don't get any errors, but whenever it runs, it acts like the file doesn't exist and creates a new one named finances.txt, which in turn erases all of the text that was in the original. I have done this correctly before and just can't remember what I did and what I am doing incorrectly here.
I am a little confused as to what exactly you are trying to do?
Are you trying to append to the file? Because when you call
ofstream print(name) you are writing over the file that you are reading in.
So if you want to append to that same file you have to add.
fstream::app in the declaration of the ofstream

fstream won't print to file

The following code will print something to a file
std::fstream fout ("D_addr.txt", std::fstream::app);
fout << pkt->Addr() << std::endl;
flush(fout);
fout.close();
While debugging, I watched pkt->Addr() and it has some values. The fout line is passed without problem. Also the file D_addr.txt is created. However after closing the file, the file size is zero! nothing has been written to it.
Where is the problem?
This is not your actual code I guess and if it is I would start with that Addr() function of yours.
Note that fstream::close "closes the file currently associated with the object, disassociating it from the stream. Any pending output sequence is written to the physical file." flush(fout); can be omitted.
You should also specify std::fstream::out flag. "If the function is called with any value in that parameter the default mode is overridden, not combined." So instead of std::fstream::app you should pass std::fstream::app | std::fstream::out.
I'm wondering if you're not using the wrong class. If you want to write to a file, use std::ofstream, and not std::fstream. In particular, the constructor of std::ofstream forces the ios_base::out bit when calling rdbuf()->open; the constructor of std::fstream doesn't (so you're opening the file with neither read nor write access).
And you probably want to check the error status: did the open succeed, and after the close (or the flush), did all of the writes succeed. The usual way of doing this is just:
if ( fout ) {
// All OK...
}
if ( !fout ) {
// Something went wrong.
}
After the open (the constructor), you can use fout.is_open(), which has the advantage of being a little bit more explicit with regards to what you are checking for.
First of all, flush() and fout.close() do not make any harm, but are not needed here, because when fout gets destroyed the file will be closed (and flushed) as part of fstream destructor.
Second, you should use an ofstream or alternatively add the flag std::ios::out to the openmode parameter.
Try something along the lines of:
{
uint64_t x = 42;
std::fstream of("test.txt", std::ios::app);
of << x << std::endl;
}

Write and read object of class into and from binary file

I try to write and read object of class into and from binary file in C++. I want to not write the data member individually but write the whole object at one time. For a simple example:
class MyClass {
public:
int i;
MyClass(int n) : i(n) {}
MyClass() {}
void read(ifstream *in) { in->read((char *) this, sizeof(MyClass)); }
void write(ofstream *out){ out->write((char *) this, sizeof(MyClass));}
};
int main(int argc, char * argv[]) {
ofstream out("/tmp/output");
ifstream in("/tmp/output");
MyClass mm(3);
cout<< mm.i << endl;
mm.write(&out);
MyClass mm2(2);
cout<< mm2.i << endl;
mm2.read(&in);
cout<< mm2.i << endl;
return 0;
}
However the running output show that the value of mm.i supposedly written to the binary file is not read and assigned to mm2.i correctly
$ ./main
3
2
2
So what's wrong with it?
What shall I be aware of when generally writing or reading an object of a class into or from a binary file?
The data is being buffered so it hasn't actually reached the file when you go to read it. Since you using two different objects to reference the in/out file, the OS has not clue how they are related.
You need to either flush the file:
mm.write(&out);
out.flush()
or close the file (which does an implicit flush):
mm.write(&out);
out.close()
You can also close the file by having the object go out of scope:
int main()
{
myc mm(3);
{
ofstream out("/tmp/output");
mm.write(&out);
}
...
}
Dumping raw data is a terrible idea, from multiple angles. This will break even worse once you add pointer data.
One suggestion would be to use Boost.Serialization which allows for far more robust data dumping.
Your main problem is the file does not contain the contents yet due to fstream buffering. Close or flush the file.
I'll echo "you shouldn't be doing this". If you print out sizeof(myc) in the code above it's probably 4, as you'd expect... BUT try changing read and write to be virtual. When I did so, it prints out the size as 16. Those 12 bytes are internal guts with sensitive values—and saving them out and then reading them back in would be like expecting a pointer value to be still good if you wrote it and loaded it again.
If you want to circumvent serialization and map C++ object memory directly to disk, there are ways to hack that. But rules are involved and it's not for the faint of heart. See POST++ (Persistent Object Storage for C++) as an example.
I'll add that you did not check the fail() or eof() status. If you had you'd have known you were misusing the fstream API. Try it again with:
void read(ifstream *in) {
in->read((char *) this, sizeof(myc));
if (in->fail())
cout << "read failed" << endl;
}
void write(ofstream *out){
out->write((char *) this, sizeof(myc));
if (out->fail())
cout << "write failed" << endl;
}
...and see what happens.
My C++ is pretty rust and highly under-tested, but you may want to take a look at Serialization and Unserialization. FAQ
I've done something similar using output.write((char*)&obj, sizeof(obj)), obj being an instance of your class. You may want to loop this if you want to write the data inside the object instead, which would generally be the case as you need members to be readable, right ?
Same thing for reading with read function. But if you have dynamic allocation to do then with this data, you need to handle it.

Checking existence of a txt file with C++ code

First of all, i'd to establish that i do have the text file in my Folders directory. Im using visual studio and it is where my source code is compiling.
The code below should demonstate why its not working. In visual studio.
int main( const int argc, const char **argv )
{
char usrMenuOption;
const char *cFileName = argv[ 1 ];
checkName( cFileName ); // supplying the checkName function with contents of argv[1]
usrMenuOption = getUsrOption(); // calling another function
fgetc(stdin);
return 0;
}
ifstream *openInputFile( const char *cFileName )
{
// this function might be the pronblem.
ifstream *inFile;
inFile = new ifstream;
inFile->open( cFileName, ios::in );
return inFile;
}
bool checkName( const char *cFileName )
{
// it works fine if i use a regular ifstream obj and not the one from the function
ifstream *inFile;
inFile = openInputFile( cFileName );
inFile->open( cFileName, ios::in );
if ( inFile->good() )
{
return true;
}
else
{
cout << '"' << cFileName << '"' << ": File does not exist! " << endl;
return false;
}
}
It does work if i use a non-pointer object for the ifstream.
however i need to open all of my input files this way, using the function i made.
I'm a little confused because i did not have this issue compiling in dev-cpp
You have a few options:
The one you've tried - opening the file.
Using stat.
Using GetFileAttributes.
Using FindFirstFile.
The only way to guarantee that it exists and that you can use it is to open it. If you use other methods you end up with a race condition (because the file could be deleted or locked after you check to see if it exists.
EDIT: You have a couple of other issues in your code. Firstly, you allocate a infile via new, but you never delete it. Secondly, you call open twice.
That's a poor way to test for existence: because if the file is open by another process, then the file exists but you can't open it.
A better way to test might be to use the GetFileAttributes Function: if it doesn't return INVALID_FILE_ATTRIBUTES then the file exists.
If you don't mind using Boost, there is a simple function boost::filesystem::exists( path ) that would be useful to you I guess !
I always check ifs.is_open() where ifs is a ifstream.
To check for the existence of a file (POSIX.1 compliant):
#include <unistd.h>
if (! access (file_name, F_OK))
{
// File exists.
}
How do i check if a file exists using ANSI C++?
#include <fstream>
inline bool FileExists(const char * filename)
{
return std::ifstream(filename);
}
You're trying to open the file twice inside checkName(): the first time in the constructor call inside the call to openInputFile(), the second time inside checkName() itself. Why the second call to open()?
I don't know what happens when an ifstream with an already-open file attempts to open() another file, but it won't be good, and it may well depend on the exact library implementation (hence the different behaviour between Dev-C++ and MSVC++). In short, don't do it.
There is at least one other bug: You aren't closing inFile anywhere inside checkName().
But Anyway, Do This Instead
Really, it's better not to have a separate checkName() function -- just have openInputFile() attempt to open the file, and if it fails, report the error right there and/or return a NULL pointer (or even throw an exception). That way, the operation is "atomic" -- as things stand, if the file exists at the time checkName() is called but is deleted before a subsequent call to openInputFile(), your code will get very confused.