17.7 Creating a Sequential-Access File Using Object Serialization

We begin by creating and writing serialized objects to a sequential-access file. In this section, we reuse much of the code from Section 17.3, so we focus only on the new features.

Defining the RecordSerializable Class

Let’s modify class Record (Fig. 17.3) so that objects of this class can be serialized. Class RecordSerializable (Fig. 17.8; part of the BankLibrary project) is marked with what is-known as an attribute—[Serializable] (line 7)—this attribute indicates to the CLR that RecordSerializable objects can be serialized. Classes that represent serializable types must include this attribute in their declarations or must implement interface ISerializable.

Fig. 17.8 Serializable class that represents a data record.

Alternate View

 1    // Fig. 17.8: RecordSerializable.cs
 2    // Serializable class that represents a data record.
 3    using System;
 4
 5    namespace BankLibrary
 6    {
 7       [Serializable]
 8       public class RecordSerializable
 9       {
10          public int Account { get; set; }
11          public string FirstName { get; set; }
12          public string LastName { get; set; }
13          public decimal Balance { get; set; }
14
15          // default constructor sets members to default values
16          public RecordSerializable()
17             : this(0, string.Empty, string.Empty, 0M) {}
18         
19          // overloaded constructor sets members to parameter values
20          public RecordSerializable(int account, string firstName,
21             string lastName, decimal balance)
22          {
23             Account = account;
24             FirstName = firstName;
25             LastName = lastName;
26             Balance = balance;
27          }
28       }
29    }

In a class that’s marked with the [Serializable] attribute or that implements interface ISerializable, you must ensure that every instance variable of the class is also serializable. All simple-type variables and strings are serializable. For variables of reference types, you must check the class declaration (and possibly its base classes) to ensure that the type is serializable. By default, array objects are serializable. However, if the array contains references to other objects, those objects may or may not be serializable.

Using a Serialization Stream to Create an Output File

Next, we’ll create a sequential-access file with serialization (Fig. 17.9). To test this program, we used the sample data from Fig. 17.5 to create a file named clients.ser—we chose the extension .ser to indicate that the file stores serialized objects. Since the sample screen captures are the same as Fig. 17.4, they are not shown here. Line 15 creates a BinaryFormatter for writing serialized objects. Lines 55–56 open the FileStream to which this program writes the serialized objects. The string argument that’s passed to the FileStream’s constructor represents the name and path of the file to be opened. This specifies the file to which the serialized objects will be written.

Fig. 17.9 Creating a sequential-access file using serialization.

Alternate View

  1    // Fig. 17.9: CreateFileForm.cs
  2    // Creating a sequential-access file using serialization.
  3    using System;
  4    using System.Windows.Forms;
  5    using System.IO;
  6    using System.Runtime.Serialization.Formatters.Binary;
  7    using System.Runtime.Serialization;                  
  8    using BankLibrary;
  9
 10    namespace CreateFile
 11    {
 12       public partial class CreateFileForm : BankUIForm
 13       {
 14          // object for serializing RecordSerializables in binary format
 15          private BinaryFormatter formatter = new BinaryFormatter();
 16          private FileStream output; // stream for writing to a file
 17
 18          // parameterless constructor
 19          public CreateFileForm()
 20          {
 21             InitializeComponent();
 22          }
 23         
 24          // handler for saveButton_Click
 25          private void saveButton_Click(object sender, EventArgs e)
 26          {
 27             // create and show dialog box enabling user to save file
 28             DialogResult result;
 29             string fileName; // name of file to save data
 30         
 31              using (SaveFileDialog fileChooser = new SaveFileDialog())
 32              {
 33                 fileChooser.CheckFileExists = false; // let user create file
 34         
 35                 // retrieve the result of the dialog box
 36                 result = fileChooser.ShowDialog();
 37                 fileName = fileChooser.FileName; // get specified file name
 38              }
 39         
 40              // ensure that user clicked "OK"
 41              if (result == DialogResult.OK)
 42              {
 43                 // show error if user specified invalid file
 44                 if (string.IsNullOrEmpty(fileName))
 45                 {
 46                    MessageBox.Show("Invalid File Name", "Error",
 47                       MessageBoxButtons.OK, MessageBoxIcon.Error);
 48                 }
 49                 else
 50                 {
 51                    // save file via FileStream if user specified valid file
 52                    try
 53                    {
 54                       // open file with write access
 55                       output = new FileStream(fileName,
 56                          FileMode.OpenOrCreate, FileAccess.Write);
 57                      
 58                       // disable Save button and enable Enter button
 59                       saveButton.Enabled = false;
 60                       enterButton.Enabled = true;
 61                     }
 62                     catch (IOException)
 63                     {
 64                        // notify user if file could not be opened
 65                        MessageBox.Show("Error opening file", "Error",
 66                           MessageBoxButtons.OK, MessageBoxIcon.Error);
 67                     }
 68                 }
 69              }
 70          }
 71         
 72          // handler for enterButton Click
 73          private void enterButton_Click(object sender, EventArgs e)
 74          {
 75             // store TextBox values string array
 76             string[] values = GetTextBoxValues();
 77         
 78             // determine whether TextBox account field is empty
 79             if (!string.IsNullOrEmpty(values[(int) TextBoxIndices.Account]))
 80             {
 81                // store TextBox values in RecordSerializable and serialize it
 82                try
 83                {
 84                   // get account-number value from TextBox
 85                   int accountNumber = int.Parse(
 86                      values[(int) TextBoxIndices.Account]);
 87            
 88                   // determine whether accountNumber is valid
 89                   if (accountNumber > 0)
 90                   {
 91                      // RecordSerializable to serialize
 92                      var record = new RecordSerializable(accountNumber,
 93                         values[(int) TextBoxIndices.First],
 94                         values[(int) TextBoxIndices.Last],
 95                         decimal.Parse(values[(int) TextBoxIndices.Balance]));
 96            
 97                       // write Record to FileStream (serialize object)
 98                       formatter.Serialize(output, record);
 99                   }
100                   else
101                   {
102                       // notify user if invalid account number
103                       MessageBox.Show("Invalid Account Number", "Error",
104                          MessageBoxButtons.OK, MessageBoxIcon.Error);
105                    }
106                }
107                catch (SerializationException)
108                {
109                   MessageBox.Show("Error Writing to File", "Error",
110                      MessageBoxButtons.OK, MessageBoxIcon.Error);
111                }
112                catch (FormatException)
113                {
114                   MessageBox.Show("Invalid Format", "Error",
115                      MessageBoxButtons.OK, MessageBoxIcon.Error);
116                }
117             }
118         
119              ClearTextBoxes(); // clear TextBox values
120          }
121         
122          // handler for exitButton Click
123          private void exitButton_Click(object sender, EventArgs e)
124          {
125             // close file
126             try
127             {
128                 output?.Close(); // close FileStream
129             }
130             catch (IOException)
131             {
132                 MessageBox.Show("Cannot close file", "Error",
133                    MessageBoxButtons.OK, MessageBoxIcon.Error);
134             }
135         
136             Application.Exit();
137          }
138       }
139    }

This program assumes that data is input correctly and in record-number order. Method enterButton_Click (lines 73–120) performs the write operation. Lines 92–95 create and initialize a RecordSerializable object. Line 98 calls Serialize to write the RecordSerializable object to the output file. Method Serialize takes the FileStream object as the first argument so that the BinaryFormatter can write its second argument to the correct file. The app does not specify how to format the objectfor output—Serialize handles these details. If a problem occurs during serialization, a SerializationException occurs.

In the sample execution (Fig. 17.9), we entered five accounts—the same as in Fig. 17.5. The program does not show how the data records actually appear in the file. Remember that we are now using binary files, which are not human readable. To verify that the file was created successfully, the next section presents a program to read the file’s contents.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset