Writing object into binary file

I have a linked list object, which I want to write the contents of into a binary file.

The way I learned how to write into binary file is using this method:

1
2
3
4
ofstream b(name, ios::out | ios::binary);
	b.write((char*)&x, sizeof(x));
	b.write((char*)&y, sizeof(y));
	b.close();


Where x is an int data type, and y is a double data type.

The object I want to write contains 4 values, 2 ints and 2 strings. If I use the same method as above, will it successfully write onto the file?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
void readFile(string name, Patient temp);
int main()
{
	int val;
	int doc;
	string fname, lname;
	char choice;
	char choice2;
	Patient Standard;
	Patient Emergency;

	do
	{
		cout << "A) Add new value\nP) Print current list\nQ) Quit" << endl;
		cin >> choice;
		if (choice == 'a' || choice == 'A')
		{
			cout << "New value: "; cin >> val; cout << endl;
			cout << "New doctor ID: "; cin >> doc; cout << endl;
			cout << "First Name: "; cin >> fname; cout << endl;
			cout << "Last Name: "; cin >> lname; cout << endl;

			cout << "S) Standard \nE) Emergency" << endl;
			cin >> choice2;
			choice2 = tolower(choice2);
			if (choice2 == 's')
			{
				Standard.addValue(val, doc, fname, lname);
			}
			else if (choice2 == 'e')
			{
				Emergency.addValue(val, doc, fname, lname);
			}
		}
	} while (choice != 'q' && choice != 'Q');
	cout << "Printing result of Standard..." << endl;
	Standard.print(); cout << endl;
	cout << "Print result of Emergency... " << endl;
	Emergency.print();
	cout << endl;
	cout << "Reading into binary file..." << endl;
	readFile("BFile.bin", Standard);
	

	system("PAUSE");
	return 0;
}

void readFile(string name, Patient temp)
{
	ofstream file(name, ios::out | ios::binary);
	file.write((char*)&temp, sizeof(temp));
	file.close();
}


As you can see here I am passing the object by value, not by reference, does this matter?
If I use the same method as above, will it successfully write onto the file?

No. You say Patient contains 2 strings (you haven't shown us it's declaration).

std::string is a complex data type that contains a pointer to the string in memory. What you're going to write out is the contents of the string data type which does NOT include the actual string. When you attempt to read that back in the pointer will point to garbage.

As you can see here I am passing the object by value, not by reference, does this matter?

No. It will be garbage either way.


What is a Patient? If Patient contains any non-trivial data members, like std::string, you can't use the fout.write().

By the way why is readFile() writing to a file?
The patient class looks like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

class NodeType
{
private:
	int value;
	int doctorID;
	string first;
	string last;
	NodeType *next;
	friend class Patient;
};

class Patient
{
private:
	NodeType *head;
public:
	Patient();
	bool empty();
	void addValue(int, int, string, string);
	void addFront(int, int, string, string);
	void removeValue(int);
	void print();
	~Patient();
};
Patient::Patient()
{
	head = NULL;
}
bool Patient::empty()
{
	if (head == NULL)
	{
		return true;
	}
	else false;
}
void Patient::addValue(int val, int dID, string F, string L)
{
	NodeType *ptr = new NodeType;
	ptr->value = val;
	ptr->doctorID = dID;
	ptr->first = F;
	ptr->last = L;
	ptr->next = NULL;
	//if list is empty
	if (head == NULL)
	{
		head = ptr; //head points to ptr
	}
	else
	{
		NodeType *current = head; //to traverse
		while (current->next != NULL)
		{
			current = current->next; 
		}
		//reaches the end of the list
		current->next = ptr; //how current next points to ptr, ptr next points to null
	}
	ptr = NULL;
}
void Patient::addFront(int val, int dID, string F, string L)
{
	NodeType *ptr = new NodeType;
	ptr->value = val;
	ptr->doctorID = dID;
	ptr->first = F;
	ptr->last = L;
	ptr->next = NULL;
	if (empty())
	{
		head = ptr;
	}
	else
	{
		head = ptr;
		ptr->next = head->next; //ptr next points to the next node from head
	}
	ptr = NULL;
}
void Patient::print() 
{
	if (head == NULL)
	{
		cout << "List is empty, nothing to print!" << endl;
	}
	else
	{
		NodeType *current = head;
		while (current)
		{
			cout << current->first << " " << current->last << endl;
			cout << current->value << " " << current->doctorID << endl;
			for (int i = 0; i < 30; i++)
			{
				cout << "*";
			}
			cout << endl;
			current = current->next;
		}

	}
}
Patient::~Patient()
{
	NodeType *current = head;
	while (current)
	{
		NodeType *garbage = current;
		current = current->next;
		delete garbage;
	}
	current = NULL;
	head = 0;
}


it's just a basic linked list

I am creating a function to read a file because I think it's good practice, instead of a function should I make the readFile as a member function of the class?

I am creating a function to read a file because I think it's good practice,

I wasn't questioning the use of a function, I was questioning a function that is named readFile(), that is actually writing to the file.

instead of a function should I make the readFile as a member function of the class?

This is a design decision. Normally if the function doesn't need direct access to the class private member functions you should consider making it a "free" function. If it does require direct access direct access to the private member variables then consider a class member function.

So to answer your question about using ostream.write(), you can't directly write() this class to a file using the write() function because all you have is a pointer member variable. Using write will only write the value of the pointer, not the actual data.

In this program I would create a "print" function in the Node class that properly serializes the data that is held in the class. Remember you can't just write the string members, because they are non-trivial types. And because the string lengths can vary you need to first write the length to the file before you write the string.data() to the file.

I would recommend that you consider using a normal text file instead of the binary file unless you need random file access.



I still don't understand what you are asking about the readFile, it is a function which is supposed to write data onto a binary

I am using binary because it is slightly more complex than writing onto a text file so it's just for good practice


Yeah I'm not going to write the pointer, but the variables which the pointer points, so for example

Patient->info
Patient->first
Patient->last

What do you mean by serializes, what does that mean. I have a print function in my Node class, but it prints out the values of the pointers it doesn't "serialize" whatever that means

Hm so you can't write strings onto a binary file?... how would you write a string onto a binary file then? I'm confused
I still don't understand what you are asking about the readFile, it is a function which is supposed to write data onto a binary

You really don't see the inconsistency there?

Nah to me readFile means to read into the file, it's just the way I like to label the function, but the purpose is to just write onto the file

I get how it may seem backwards to others but it just works for me

So the main problem is still there, how could I write my patient object onto a binary file

I think writing a function that prepares a 'presentable' string for the appropriate classes should do the trick. You can then call those functions with a member of the linked list.
What do you mean by serializes, what does that mean. I have a print function in my Node class, but it prints out the values of the pointers it doesn't "serialize" whatever that means

See this link:
https://isocpp.org/wiki/faq/serialization


Hm so you can't write strings onto a binary file?... how would you write a string onto a binary file then? I'm confused


Basically the way I handle std::string and binary files is to first write the length of the string, then write the string.c_str().

Something like:
1
2
3
4
5
6
7
8
9
   // This function only writes a std::string to the file.
   void writeVal(std::ostream &fout, const std::string &str)
   {
      size_t len = str.size();
      // Write the length of the string to the file so we can read the string.
      fout.write(reinterpret_cast<char*>(&len), sizeof(len));
      // Write the string to the file.
      fout.write(reinterpret_cast<const char*>(str.c_str()), len);
   }

Reading is the opposite, read the length, then read length characters into a string.
Even I had the same problem ,the best and efficient way I came up with this type of problem is the write the data to text file.While writing each node's data to the text remove the node from the linked list.In the same way ,while reading data from the file create a new node to the linked list.

Use the following for reading and writing.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
void stu::write()
{
 student *temp=head;
 ofstream out;
 out.open(fn,ios::trunc);
 while(temp!=NULL)
 {
  out<<temp->value<<" "<<temp->doctorId<<" "<<temp->first<<" "<<temp->last;
  temp=temp->next;
 }
 out.close();
}


void stu::read()
{
 head=NULL;
 last=NULL;
 if(access(fn,0)==0)
 {
  ifstream in;
  in.open(fn);
  in.seekg(0,ios::beg);
  student *New1,*prev;
  while(!in.eof())
  {
   New1=new student;
   New1->next=NULL;
   in>>New1->value>>New1->doctorId>>New1->first>>New1->last;
   if(head==NULL)
   {
    head=New1;
    last=New1;
   }
   else
   {
    prev=last;
    last->next=New1;
    last=New1;
   }
  }
  last=prev;
  last->next=NULL;
  in.close();
 }
 else
  cout<<"\nNew file is created!!";
}
Topic archived. No new replies allowed.