FunctionX Tutorials

File Processing: C++' Object Serialization

 

Introduction

Object serialization consists of saving the values that are part of an object, mostly the value gotten from declaring a variable of a class. At the current standard, C++ doesn't inherently support object serialization. To perform this type of operation, you can use a technique known as binary serialization.

When you decide to save a value to a medium, the fstream class provides the option to save the value in binary format. This consists of saving each byte to the medium by aligning bytes in a contiguous manner, the same way the variables are stored in binary numbers.

 

Practical Learning: Introduction C++ Binary Serialization

  1. Start Microsoft Visual C++
  2. Create a new project named ROSH1
  3. Create the project as a Dialog Based and set the Dialog Title as Red Oak High School
  4. Click Finish and design the dialog box as follows:
     
    Control ID Caption Additional Properties
    Group Box     Identification  
    Static Text     Student Name:  
    Edit Control IDC_STUDENTNAME    
    Static Text     School Year:  
    Edit Control   IDC_SCHOOLYEAR1   Align Text: Right
    Number: True
    Static Text     /  
    Edit Control   IDC_SCHOOLYEAR2   Align Text: Right
    Number: True
    Group Box     Grades  
    Static Text     English:  
    Edit Control   IDC_ENGLISH    Align Text: Right
    Static Text     History:  
    Edit Control   IDC_HISTORY   Align Text: Right
    Static Text     Economics:  
    Edit Control   IDC_ECONOMICS   Align Text: Right
    Static Text     2nd Language:  
    Edit Control   IDC_2NDLANGUAGE    Align Text: Right
    Static Text     Geography:  
    Edit Control   IDC_GEOGRAPHY   Align Text: Right
    Static Text     Arts:  
    Edit Control   IDC_ARTS   Align Text: Right
    Static Text     Math:  
    Edit Control   IDC_MATH    Align Text: Right
    Static Text     Science:  
    Edit Control   IDC_SCIENCE   Align Text: Right
    Static Text     Phys. Educ.:  
    Edit Control   IDC_PHYSEDUC   Align Text: Right
    Group Box     Grade Processing  
    Button   IDC_CALCULATE Calculate  
    Static Text     Total:  
    Edit Control   IDC_TOTAL   Align Text: Right
    Static Text     Average:  
    Edit Control   IDC_AVERAGE   Align Text: Right
    Button   IDC_SAVE Save  
    Button   IDC_OPEN Open  
    Button   IDCANCEL Close  
  5. Using either the ClassWizard or the Add Member Variable Wizard, add the following member variables to the controls:
     
    ID Value Variable Control Variable
    Type Name
    IDC_STUDENTNAME CString m_StudentName  
    IDC_SCHOOLYEAR1 int m_SchoolYear1  
    IDC_SCHOOLYEAR2 int m_SchoolYear2  
    IDC_ENGLISH double m_English  
    IDC_HISTORY double m_History  
    IDC_ECONOMICS double m_Economics  
    IDC_2NDLANGUAGE double m_2ndLanguage  
    IDC_GEOGRAPHY double m_Geography  
    IDC_ARTS double m_Arts  
    IDC_MATH double m_Math  
    IDC_SCIENCE double m_Science  
    IDC_PHYSEDUC double m_PhysEduc  
    IDC_TOTAL double m_Total  
    IDC_AVERAGE double m_Average  
  6. On the dialog box, double-click the Calculate button and implement its event as follows:
     
    void CROSH1Dlg::OnBnClickedCalculate()
    {
    	// TODO: Add your control notification handler code here
    	UpdateData();
    	double English, History, Economics,
    		   Language2, Geography, Arts,
    		   Math, Science, PhysEduc;
    	double Total, Average;
    
    	English   = this->m_English;
    	History   = this->m_History;
    	Economics = this->m_Economics;
        	Language2 = this->m_2ndLanguage;
    	Geography = this->m_Geography;
    	Arts      = this->m_Arts;
    	Math	  = this->m_Math;
    	Science   = this->m_Science;
    	PhysEduc  = this->m_PhysEduc;
    
    	Total = English + History + Economics +
    		   Language2 + Geography + Arts +
    		   Math + Science + PhysEduc;
    	Average = Total / 9;
    	
    	this->m_Total = Total;
    	this->m_Average = Average;
    	UpdateData(FALSE);
    }
  7. After using it, close it and return to your programming environment.

Saving Values in Binary Format

To indicate that you want to save a value as binary, when declaring the ofstream variable, specify the ios option as binary. Here is an example:

#include <fstream>
#include <iostream>
using namespace std;

class Student
{
public:
	char   FullName[40];
	char   CompleteAddress[120];
	char   Gender;
	double Age;
	bool   LivesInASingleParentHome;
};

int main()
{
	Student one;

	strcpy(one.FullName, "Ernestine Waller");
	strcpy(one.CompleteAddress, "824 Larson Drv, Silver Spring, MD 20910");
	one.Gender = 'F';
	one.Age = 16.50;
	one.LivesInASingleParentHome = true;
	
	ofstream ofs("fifthgrade.ros", ios::binary);

	return 0;
}

 

Practical Learning: Specifying Binary Format

  1. In the source file of the program, create a structure named CStudentGrade and that has a member variable equivalent to each value in the dialog box:
     
    // ROSH1Dlg.cpp : implementation file
    //
    
    #include "stdafx.h"
    #include "ROSH1.h"
    #include "ROSH1Dlg.h"
    #include ".\rosh1dlg.h"
    
    #include <fstream>
    using namespace std;
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    
    
    // CROSH1Dlg dialog
    
    struct CStudentGrade
    {
    	CString StudentName;
    	int        SchoolYear1;
    	int        SchoolYear2;
    	double English;
    	double History;
    	double Economics;
    	double Language2;
    	double Geography;
    	double Arts;
    	double Math;
    	double Science;
    	double PhysEduc;
    	double Total;
    	double Average;
    };
  2. Return to the dialog box and double-click the Save button
  3. Implement its event as follows:
     
    void CROSH1Dlg::OnBnClickedSave()
    {
    	// TODO: Add your control notification handler code here
    	CStudentGrade StdGrades;
    	CString strFilename = this->m_StudentName + ".dnt";
    
    	ofstream ofs(strFilename, ios::binary);
    }
  4. Save all

Writing to the Stream

The ios::binary option lets the compiler know how the value will be stored. This declaration also initiates the file. To write the values to a stream, you can call the fstream::write() method.

After calling the write() method, you can write the value of the variable to the medium. Here is an example:

#include <fstream>
#include <iostream>
using namespace std;

class Student
{
public:
	char   FullName[40];
	char   CompleteAddress[120];
	char   Gender;
	double Age;
	bool   LivesInASingleParentHome;
};

int main()
{
	Student one;

	strcpy(one.FullName, "Ernestine Waller");
	strcpy(one.CompleteAddress, "824 Larson Drv, Silver Spring, MD 20910");
	one.Gender = 'F';
	one.Age = 16.50;
	one.LivesInASingleParentHome = true;
	
	ofstream ofs("fifthgrade.ros", ios::binary);

	ofs.write((char *)&one, sizeof(one));

	return 0;
}
 

Practical Learning: Writing to the Stream

  1. Change the code of the Save button as follows:
     
    void CROSH1Dlg::OnBnClickedSave()
    {
    	// TODO: Add your control notification handler code here
    	UpdateData();
    	CStudentGrade StdGrades;
    
    	// Save a student's grades only if the record contains a name
    	if( this->m_StudentName == "" )
    		return;
    	// Don't save the record if the school year is not known or is not valid
    	if( this->m_SchoolYear1 < 1900 )
    		return;
    	if( this->m_SchoolYear2 != (this->m_SchoolYear1 + 1) )
    		return;
    
    	// Initialize the student with the values from the dialog box
    	strcpy(StdGrades.StudentName, this->m_StudentName);
    	StdGrades.SchoolYear1 = this->m_SchoolYear1;
    	StdGrades.SchoolYear2 = this->m_SchoolYear2;
    	StdGrades.English     = this->m_English;
    	StdGrades.History     = this->m_History;
    	StdGrades.Economics   = this->m_Economics;
    	StdGrades.Language2   = this->m_2ndLanguage;
    	StdGrades.Geography   = this->m_Geography;
    	StdGrades.Arts        = this->m_Arts;
    	StdGrades.Math        = this->m_Math;
    	StdGrades.Science     = this->m_Science;
    	StdGrades.PhysEduc    = this->m_PhysEduc;
    	StdGrades.Total       = this->m_Total;
    	StdGrades.Average     = this->m_Average;
    
    	CString strFilename = this->m_StudentName;
    	CFile fleGrades;
    	char strFilter[] = { "Student Grades (*.dnt)|*dnt|All Files (*.*)|*.*||" };
    	CFileDialog dlgFile(FALSE, ".dnt", strFilename, 0, strFilter);
    
    	if( dlgFile.DoModal() == IDOK )
    	{
    		// Save the record in binary format
    		ofstream stmGrades(dlgFile.GetFileName(), ios::binary);
    		stmGrades.write((char *)&StdGrades, sizeof(StdGrades));
    
    		// Reset the dialog box in case the user wants to enter another record
    		m_StudentName = "";
    		m_SchoolYear1 = 2000;
    		m_SchoolYear2 = 2001;
    		m_English     = 0.00;
    		m_History     = 0.00;
    		m_Economics   = 0.00;
    		m_2ndLanguage = 0.00;
    		m_Geography   = 0.00;
    		m_Arts        = 0.00;
    		m_Math        = 0.00;
    		m_Science     = 0.00;
    		m_PhysEduc    = 0.00;
    		m_Total       = 0.00;
    		m_Average     = 0.00;
    	}
    
    	UpdateData(FALSE);
    }
  2. Execute the application
  3. Enter sample grades for a student and click Calculate
     
    Red Oak High School - Student Grades
  4. Click the Save button. Accept the default name of the file and click Save
  5. Close the dialog box and return to your programming environment

Reading From the Stream

Reading an object saved in binary format is as easy as writing it. To read the value, call the ifstream::read() method. Here is an example:

#include <fstream>
#include <iostream>
using namespace std;

class Student
{
public:
	char   FullName[40];
	char   CompleteAddress[120];
	char   Gender;
	double Age;
	bool   LivesInASingleParentHome;
};

int main()
{
/*	Student one;

	strcpy(one.FullName, "Ernestine Waller");
	strcpy(one.CompleteAddress, "824 Larson Drv, Silver Spring, MD 20910");
	one.Gender = 'F';
	one.Age = 16.50;
	one.LivesInASingleParentHome = true;
	
	ofstream ofs("fifthgrade.ros", ios::binary);

	ofs.write((char *)&one, sizeof(one));
*/
	Student two;

	ifstream ifs("fifthgrade.ros", ios::binary);
	ifs.read((char *)&two, sizeof(two));

	cout << "Student Information\n";
	cout << "Student Name: " << two.FullName << endl;
	cout << "Address:      " << two.CompleteAddress << endl;
	if( two.Gender == 'f' || two.Gender == 'F' )
		cout << "Gender:       Female" << endl;
	else if( two.Gender == 'm' || two.Gender == 'M' )
		cout << "Gender:       Male" << endl;
	else
		cout << "Gender:       Unknown" << endl;
	cout << "Age:          " << two.Age << endl;
	if( two.LivesInASingleParentHome == true )
		cout << "Lives in a single parent home" << endl;
	else
		cout << "Doesn't live in a single parent home" << endl;
	
	cout << "\n";

	return 0;
}
 

Practical Learning: Reading From the Stream

  1. On the dialog box, double-click the Open button and implement its event as follows:
     
    void CROSH1Dlg::OnBnClickedOpen()
    {
    	// TODO: Add your control notification handler code here
    	UpdateData();
    
    	CStudentGrade StdGrades;
    	CFile fleGrades;
    	char strFilter[] = { "Student Grades (*.dnt)|*dnt|All Files (*.*)|*.*||" };
    	CFileDialog dlgFile(TRUE, ".dnt", NULL, 0, strFilter);
    
    	if( dlgFile.DoModal() == IDOK )
    	{
    		// Open a record in binary format
    		ifstream stmGrades(dlgFile.GetFileName(), ios::binary);
    		stmGrades.read((char *)&StdGrades, sizeof(StdGrades));
    
    		// Change the caption of the dialog box to reflect the current grade
    		char name[40];
    		strcpy(name, StdGrades.StudentName);
    		CString caption;
    		caption.Format("Red Oak High School: %s", name);
    		this->SetWindowText(caption);
    
    		// Display the record in the dialog box
    		this->m_StudentName.Format("%s", name);
    		this->m_SchoolYear1 = StdGrades.SchoolYear1;
    		this->m_SchoolYear2 = StdGrades.SchoolYear2;
    		this->m_English     = StdGrades.English;
    		this->m_History     = StdGrades.History;
    		this->m_Economics   = StdGrades.Economics;
    		this->m_2ndLanguage = StdGrades.Language2;
    		this->m_Geography   = StdGrades.Geography;
    		this->m_Arts        = StdGrades.Arts;
    		this->m_Math        = StdGrades.Math;
    		this->m_Science     = StdGrades.Science;
    		this->m_PhysEduc    = StdGrades.PhysEduc;
    		this->m_Total       = StdGrades.Total;
    		this->m_Average     = StdGrades.Average;
    	}
    
    	UpdateData(FALSE);
    }
  2. Execute the application and open the previously saved record
  3. Close the form

 

 

Home Copyright 2004 FunctionX. Inc.