c++ serialization of a structure - c++

While compiling this simple code:
#include <fstream>
#include <iostream>
#include <string.h>
using namespace std;
class Example
{
public:
char charo;
int into;
};
int main()
{
Example one,two;
one.charo = 'X'; one.into = 2;
//WRITING
ofstream file;
file.open("my.prx", ios_base::binary);
if(file.good()) file.write((char*)&one, sizeof(Example));
else cout << "ERROR WHILE OPENING FILE" << endl;
file.close();
//READING
file.open("my.prx", ios_base::binary);
if(file.good())
file.read((char*)&two, sizeof(Example));
else cout << "ERROR WHILE OPENING FILE" << endl;
file.close();
//PRINTING
cout << "CHAR: " << two.charo << endl;
cout << "INT: " << two.into << endl;
}
I get this error message:
g++ -o test1 main.c main.c: In function ‘int main()’: main.c:43:7:
error: ‘std::ofstream’ has no member named ‘read’
file.read((char*)&two, sizeof(Example));
How can I solve it?
My next step will be to make a more complicated object to save:
Class Memory{
t_monitor monitors[MAX_MONITORS];
t_status status[MAX_STATUS];
t_observer observers[MAX_OBSERVERS];
Var * first_var;
int tot_observers;
int tot_status;
int tot_monitors;
};
As you can see there is also a list...

ofstream is an output file stream. It's used for output, and can't "read".
Use fstream instead.

Use ifstream to read ostream is used for output.
You can do something like this
std::ifstream fileRead( "my.prx",std::ifstream::binary );
if(fileRead)
fileRead.read((char*)&two, sizeof(Example));
else cout << "ERROR WHILE OPENING FILE" << endl;
fileRead.close();

An [ofstream][1] is output only. One readable way is to use the variables ofstream ofile and ifstream ifile. This way the usage is clear from the declaration and the name. If the code grows, this might be helpful.
Another way would be to use the dual-use fstream, but this can make certain operations ambiguous.
Of course, these days, you're probably better off using some sort of serialization library. First, preferring the one that your company or group already uses, and then, if that one is inadequate, picking a modern lib like Boost or, my fave, Cereal.

Related

How to create an object using bytes read from a binary file in C++? [duplicate]

This question already has answers here:
Is it possible to serialize and deserialize a class in C++?
(14 answers)
Closed 2 years ago.
Let there be a C++ struct S of which an instance is created and written to a binary file. Then said file is read back into the program and an instance should be created from it. How is this second part achieved?
Here is the definition of S:
struct S {
int value;
string txt;
};
Now to create a binary file with the data for one such struct, the following function is used:
int writeStructAsBinary() {
ofstream ofs;
S s;
s.txt = "Hello World";
s.value = 10;
ofs.open("output.dat", ios::out | ios::binary);
if (!ofs.good()) { cerr << "Error opening file." << endl; return 1; }
ofs.write((char*)&s, sizeof(S));
ofs.close();
return 0;
}
I'm a bit unsure if the (char*)&s is correct but that's what I got.
Now how can I read the data from the output.dat file back into the program? In principle it should just be "read sizeof(S) bytes", but how do I create a Struct from the bytes? Here's my attempt?
int readAndPrintBinary() {
ifstream ifs;
ifs.open("output.dat", ios::in | ios::binary);
if (!ifs) { cerr << "Could not open file." << endl; return 1; }
ifs.seekg(0, ios::beg);
char* binaryInstance = new char[sizeof(S)];
ifs.read(binaryInstance, sizeof(S));
ifs.close();
delete binaryInstance;
return 0;
}
I'd like to now confirm s.txt and s.value. How can I do that?
The main program is this:
#include <iostream>
#include <string>
#include <sstream>
#include <string>
#include <fstream>
using namespace std;
int main() {
writeStructAsBinary();
readAndPrintBinary();
}
Using reinterpret_cast to recreate the object:
int readAndPrintBinary() {
ifstream ifs;
ifs.open("output.dat", ios::in | ios::binary);
if (!ifs) { cerr << "Could not open file." << endl; return 1; }
ifs.seekg(0, ios::beg);
char* binaryInstance = new char[sizeof(S)];
ifs.read(binaryInstance, sizeof(S));
S* s = reinterpret_cast<S*>(binaryInstance);
ifs.close();
cout << "s->txt = " << s->txt << endl;
cout << "s->value = " << s->value << endl;
delete[] binaryInstance;
return 0;
}
You can't do this if S has a member of non-POD type, which it does: std::string. It's going to invoke undefined behavior, and almost certainly crash.
If S were a POD type, you'd re-create the object by doing:
S *s = reinterpret_cast<S*>(binaryInstance);
You then have to make sure you never delete s, but only call delete[] binaryInstance;
Remember that structs may have padding as well, so you may be writing out a bunch of useless padding bytes (which in the worst case may contain junk from the heap that could lead to security implications for your program!!)
Your much safer alternative here is to just persist the members of S directly, one by one. It's more code, yes, but much safer and more portable.

fstream test program crashes for some reason

I have been playing around with the fstream class in C++ to see if I am able to write some data to a text file(.txt). According to what I know, If the program tries to write to a file that does not exist then it would automatically create that file, am I wrong? This program is very simple and does not give me any compiler errors which means it builds fine. However for some reason it crashes when I run it.
Here is my code:
#include <iostream>
#include <string>
#include <stdlib.h>
#include <fstream>
std::fstream* myFile;
int main()
{
int age = 15;
std::string myName = "Javier Martinez";
std::string friendsName = "David Lyn";
//Backslash is a special character, use double backslash or forward slash instead.
myFile->open("C:/Users/NIKE/Desktop/data.txt");
if (myFile->fail())
{
std::cerr << "File was unable to be opened.";
}
*myFile << age << "\n";
*myFile << myName << "\n";
*myFile << friendsName << "\n";
myFile->close();
std::cout << "File was successfully written to with the data";
return 0;
}
Any help is appreciated. Thank you in advance.
NOTE: I am using the GNU GCC compiler with Code::Blocks IDE
myFile is uninitialized. Check it.( Allocate memory) or simply use fstream.
Your problem stems from the line:
std::fstream* myFile;
You only declared a pointer to a stream object, which is initialized to nullptr by reason of it being in the global scope. The fact that you tried accessing a non-existent object (invalid) through it, you invoked what is known as Undefined Behavior.
You do not need to allocate stream objects on the heap, rather, do:
std::fstream myFile;
On a side Note: Check your program control flow:
if (!myFile)
{
std::cerr << "File was unable to be opened.";
}
else{
myFile << age << "\n";
myFile << myName << "\n";
myFile << friendsName << "\n";
}

c++ fstream read() function not working

Why my following code fails to read single integer from file?
It displays "fail() reading" followed by "0".
On linux ubuntu gcc compiler.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ofstream fout2("int_data",ios::binary|ios::out);
int a = 2;
fout2.write((char*)&a,sizeof(a));
int b=0;
ifstream fin2("int_data",ios::binary|ios::in);
fin2.read((char*)&b,sizeof(b));
if(fin2.fail())
cout << "fail() reading" << endl;
cout << b << endl;
}
This could fail for a couple reasons:
Your OS may be protecting you from opening a file that is currently opened for writing
You may not have flushed your data to the file
You can solve both of these by using close before you construct fin2:
ofstream fout2("int_data", ios::binary);
const int a = 2;
fout2.write(reinterpret_cast<const char*>(&a), sizeof(a));
fout2.close();
int b = 0;
ifstream fin2("int_data", ios::binary);
if(!fin2.read(reinterpret_cast<char*>(&b), sizeof(b))) {
cout << "fail() reading" << endl;
}
cout << b << endl;;
Live Example

ifstream not working

I'm trying to open a file using ifstream, but no matter what solutions I find that I've tried, nothing seems to work; my program always outputs "unable to open". Below is my code in its entirety. Any help at all is appreciated!
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(int argc, char ** argv)
{
string junk;
ifstream fin;
fin.open("somefile.txt");
if(fin.is_open())
{
fin >> junk;
cout << junk;
}
else
{
cout << "unable to open" << endl;
}
fin.close();
return 0;
}
Also, the contents of somefile.txt, which is in the same directory as the created executable is the following:
SOME
FILE
As some commenters have suggested, it could easily be that the file truly doesn't exist, because you're looking for it in the wrong place. Try using an absolute path to the file rather than just assuming it's looking where you expect.
And output a more helpful error message using strerror(errno).
// ...
fin.open("C:\\path\\to\\somefile.txt");
// ...
else
{
cout << "unable to open: " << strerror(errno) << endl;
}

Why doesn't my function produce output

I'm doing a C++ assingment for a class and I haven't used C++ in a decade so this might be something I'm missing that is simple; however ,I can't seem to figure it out.
I have a class I defined with a function that is producing no output; it looks like it's not even running and I don't have a clue why. Could someone point out my problem to me?
Issue: cout from the function getwords of the class readwords doesn't display any results.
Here is my class:
class readwords {
private:
char c;
//string aword;
public:
void getwords(std::istream& file) {
cout << "I got here" << std::flush;
/*while(file.good()) {
cout << "I got here\n";
c = file.get();
if(isspace(c)) cout << "\n"; //continue;
if(isalnum(c)) {
cout << c; //aword.insert(aword.end(),c);
}
}
*/
}
};
Which is being called from my main:
#include <fstream>
#include <stdlib.h>
#include "lab1.h"
using namespace std;
readwords wordsinfile;
words wordslist;
int main ( int argc, char *argv[] )
{
if ( argc != 2 ) {
// Looks like we have no arguments and need do something about it
// Lets tell the user
cout << "Usage: " << argv[0] <<" <filename>\n";
} else {
// Yeah we have arguements so lets make sure the file exists and it is readable
ifstream ourfile(argv[1]);
if (!ourfile.is_open()) {
// Then we have a problem opening the file
// Lets tell the user and exit
cout << "Error: " << argv[0] << " could not open the file. Exiting\n";
exit (1);
}
// Do we have a ASCII file?
if (isasciifile(ourfile)) {
cout << "Error: " << argv[0] << " only can handle ASCII or non empty files. Exiting\n";
exit(1);
}
// Let ensure we are at the start of the file
ourfile.seekg (0, ios::beg);
// Now lets close it up
ourfile.close();
}
// Ok looks like we have past our tests
// Time to go to work on the file
ifstream ourfile2(argv[1]);
wordsinfile.getwords(ourfile2);
}
Thank you for any help you can provide.
Try to use a debugger. Most IDEs (NetBeans, Code::Blocks, etc) provide an interactive interface with gdb.
I just compiled and ran your code, but nothing wrong with the code itself,
except that I needed to include to use the 'cout' method.
"I got here" has been successfully displayed in my ubuntu machine.
What is your execution environment? You should check it first.
The problem appears to be redefining my own class. When actually coding the function I needed to use:
in readwords::countwords(std::istream& file) {
....
}
Once doing this output produced fine.