Chapter 21 – Files and Streams 1 Outline Files and Streams Classes File and Directory Creating a Sequential-Access File Reading Data from a Sequential-Access File Random-Access Files
Files and Streams When file opened C#: Creates an object Associates a stream with that object Three stream objects: Console.In: standard input stream object Console.Out: standard output stream object Console.Error: standard error stream object Namespace System.IO needed for file processing 2
Files and Streams System.IO.Stream : allows representation of stream as bits FileStream : read to and write from sequential-access and random-access files MemoryStream : transfer of data directly to and from memory BufferedStream : uses buffer to transfer to memory 3
Classes File and Directory Data and information stored in files Files organized in directories Directory class used to manipulate directories File class used to manipulate files Only has static methods, cannot instantiate File objects 4
// Using classes File and Directory. using System.IO; private System.Windows.Forms.Label directionsLabel; private System.Windows.Forms.TextBox outputTextBox ; private System.Windows.Forms.TextBox inputTextBox; // displays contents of files and directories public partial class FileTestForm : Form { // invoked when user presses key private void inputTextBox_KeyDown( object sender, System.Windows.Forms.KeyEventArgs e ) { // determine whether user pressed Enter key if ( e.KeyCode == Keys.Enter ) { 5 Textboxes to get file or directory names Event handler for keystrokes Test if key typed was enter
// get user-specified file or directory string fileName = inputTextBox.Text; // determine whether fileName is a file if ( File.Exists( fileName ) ) { // display file contents through StreamReader try { // obtain reader and file contents StreamReader stream = new StreamReader( fileName ); outputTextBox.Text += stream.ReadToEnd(); } // handle exception if StreamReader is unavailable catch( IOException ) { MessageBox.Show( "File Error", "File Error", MessageBoxButtons.OK, MessageBoxIcon.Error ); } else { // notify user that file does not exist MessageBox.Show( inputTextBox.Text + " does not exist", "File Error", MessageBoxButtons.OK, MessageBoxIcon.Error ); } } // end if } // end method inputTextBox_KeyDown }//class }//end namespace 6 Set fileName to what user typed See if fileName is an existing file Create StreamReader to read text from file Call method ReadToEnd If user input is not existing file output error message FileTest.cs
Creating or Writing to a Sequential-Access File Programmers have to structure files to meet the requirements of applications 7
//BankUI.cs BankLibary.dll (Windows Control Library) // A reusable windows form for the examples in this chapter. public partial class BankUIForm : Form 8
// Record.cs (in BankLibrary.dll) // Serializable class that represents a data record. using System; [Serializable] public class Record { private int account; private string firstName; private string lastName; private double balance; // default constructor sets members to default values public Record() : this( 0, "", "", 0.0 ) { } // overloaded constructor sets members to parameter values public Record( int accountValue, string firstNameValue, string lastNameValue, double balanceValue ) { Account = accountValue; FirstName = firstNameValue; LastName = lastNameValue; Balance = balanceValue; } // end constructor 9 Tells compiler objects of class Record can be represented as a set of bytes Data to go into recordSets members to 0 Set members to parameters
Record.cs // property Account public int Account { get { return account; } set { account = value; } } // end property Account // property FirstName public string FirstName { get { return firstName; } set { firstName = value; } } // end property FirstName 10 Accessor methods
Record.cs // property LastName public string LastName { get { return lastName; } set { lastName = value; } } // end property LastName // property Balance public double Balance { get { return balance; } set { balance = value; } } // end property Balance } // end class Record 11 Accessor methods
// Creating a sequential-access file. // C# namespaces needed using System.IO; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization; using BankLibrary; public class CreateFileForm : BankUIForm { private System.Windows.Forms.Button saveButton; private System.Windows.Forms.Button enterButton; private System.Windows.Forms.Button exitButton; private System.ComponentModel.Container components = null; // serializes Record in binary format private BinaryFormatter formatter = new BinaryFormatter(); // stream through which serializable data is written to file private FileStream output; 12
// invoked when user clicks Save button private void saveButton_Click( object sender, System.EventArgs e ) { // create dialog box enabling user to save file SaveFileDialog fileChooser = new SaveFileDialog(); DialogResult result = fileChooser.ShowDialog(); string fileName; // name of file to save data // allow user to create file fileChooser.CheckFileExists = false; // exit event handler if user clicked "Cancel“ if ( result != DialogResult.Cancel ) { // get specified file name fileName = fileChooser.FileName; // show error if user specified invalid file if ( fileName == "" || fileName == null ) MessageBox.Show( "Invalid File Name", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error ); 13 Instantiate SaveFileDialog object Show SaveFileDialog Test if user canceled save Get file name to save to
14 SaveFileDialogue Files and directories
else { // save file via FileStream if user specified valid file try { // open file with write access output = new FileStream( fileName, FileMode.OpenOrCreate, FileAccess.Write ); // disable Save button and enable Enter button saveButton.Enabled = false; enterButton.Enabled = true; } // handle exception if file does not exist catch ( FileNotFoundException ) { // notify user if file does not exist MessageBox.Show( "File Does Not Exist", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error ); } } // end method saveButton_Click // invoke when user clicks Enter button private void enterButton_Click( object sender, System.EventArgs e ) { // store TextBox values string array string[] values = GetTextBoxValues(); // Record containing TextBox values to serialize Record record = new Record(); 15 Instantiate output stream with write permission Method to save data when user clicks enter
// determine whether TextBox account field is empty if ( values[ ( int )TextBoxIndices.ACCOUNT ] != "" ) { // store TextBox values in Record and serialize Record try { // get account number value from TextBox int accountNumber = Int32.Parse( values[ ( int )TextBoxIndices.ACCOUNT ] ); // determine whether accountNumber is valid if ( accountNumber > 0 ) { // store TextBox fields in Record record.Account = accountNumber; record.FirstName = values[ ( int )TextBoxIndices.FIRST ]; record.LastName = values[ ( int )TextBoxIndices.LAST ]; record.Balance = Double.Parse( values[( int )TextBoxIndices.BALANCE ] ); // write Record to FileStream (serialize object) formatter.Serialize( output, record ); } else { // notify user if invalid account number MessageBox.Show( "Invalid Account Number", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error ); } 16 Store TextBox fields in record Write data to file
// notify user if error occurs in serialization catch( SerializationException ) { MessageBox.Show( "Error Writing to File", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error ); } // notify user if error occurs regarding parameter format catch( FormatException ) { MessageBox.Show( "Invalid Format", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error ); } ClearTextBoxes(); // clear TextBox values } // end method enterButton_Click // invoked when user clicks Exit button private void exitButton_Click ( object sender, System.EventArgs e ) { // determine whether file exists if ( output != null ) { // close file try { output.Close(); } 17 Catch block if user input invalid data Close FileStream
// notify user of error closing file catch( IOException ) { MessageBox.Show( "Cannot close file", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error ); } Application.Exit(); } // end method exitButton_Click } // end class CreateFileForm 18 Exit program
Creating a Sequential-Access File 19 Sample data for the program
Reading Data from a Sequential-Access File Read data sequentially from a file Programs usually start at beginning of file and read data consecutively until the desired data is found Sometimes necessary to do this several times during execution of a program File-position pointer: Points to next byte to be read from or written to file Can be repositioned to any point in file This example uses a RichTextBox : LoadFile : method to display file contents Find : method for searching individual strings Can display multiple lines of text 20
// Read a file sequentially and display contents based on // account type specified by user (credit, debit or zero balances). using System.IO; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization; using BankLibrary; private System.Windows.Forms.RichTextBox displayTextBox; private System.Windows.Forms.Button doneButton; private System.Windows.Forms.Button zeroButton; private System.Windows.Forms.Button debitButton; private System.Windows.Forms.Button creditButton; private System.Windows.Forms.Button openButton; public partial class CreditInquiryForm :.Form { // stream through which serializable data are read from file private FileStream input; // object for deserializing Record in binary format BinaryFormatter reader = new BinaryFormatter(); 21
// name of file that stores credit, debit and zero balances private string fileName; // invoked when user clicks Open File button private void openButton_Click ( object sender, System.EventArgs e ) { // create dialog box enabling user to open file OpenFileDialog fileChooser = new OpenFileDialog(); DialogResult result = fileChooser.ShowDialog(); // exit event handler if user clicked Cancel if ( result != DialogResult.Cancel ) { // get name from user fileName = fileChooser.FileName; // show error if user specified invalid file if ( fileName == "" || fileName == null ) MessageBox.Show( "Invalid File Name", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error ); 22 User clicked open buttonInstantiate OpenFilelDialog Show OpenFileDialog
else { // enable all GUI buttons, except for Open file button openButton.Enabled = false; creditButton.Enabled = true; debitButton.Enabled = true; zeroButton.Enabled = true; } } // end method openButton_Click // invoked when user clicks credit balances, // debit balances or zero balances button private void get_Click ( object sender, System.EventArgs e ) { // convert sender explicitly to object of type button Button senderButton = ( Button) sender; // get text from clicked Button, which stores account type string accountType = senderButton.Text; // read and display file information try { // close file from previous operation if ( input != null ) input.Close(); // create FileStream to obtain read access to file input = new FileStream( fileName, FileMode.Open, FileAccess.Read ); displayTextBox.Text = "The accounts are:\r\n"; 23 Button click event handler Reference to object that sent event Get text from clicked button Create read only FileStream for input
// traverse file until end of file while ( true ) { // get next Record available in file Record record = ( Record )reader.Deserialize( input ); // store record's last field in balance Double balance = record.Balance; // determine whether to display balance if ( ShouldDisplay( balance, accountType ) ) { // display record string output = record.Account + "\t" + record.FirstName + "\t" + record.LastName + new string( ' ', 6 ) + "\t"; // display balance with correct monetary format output += String.Format ( "{0:F}", balance ) + "\r\n"; // copy output to screen displayTextBox.Text += output; } // handle exception when file cannot be closed catch( IOException ) { MessageBox.Show( "Cannot Close File", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error ); } 24 While loop to read from file Read input from file
// handle exception when no more records catch( SerializationException ) { // close FileStream if no Records in file input.Close(); } } // end method get_Click // determine whether to display given record private bool ShouldDisplay( double balance, string accountType ) { bool shouldDisplay = false; // display credit balances if ( ( balance > 0 ) && ( accountType == "Credit Balances" )) shouldDisplay = true; // display debit balances else if (( balance < 0 ) && ( accountType == "Debit Balances" )) shouldDisplay = true; // display zero balances else if (( balance = 0 ) && ( accountType == "Zero Balances" )) shouldDisplay = true; return shouldDisplay; } // end method ShouldDisplay 25 Method to determine whether to display each record in file No more records exception Close FileStream
CreditInquiry.cs // invoked when user clicks Done button private void doneButton_Click( object sender, System.EventArgs e ) { // determine whether file exists if ( input != null ) { // close file try { input.Close(); } // handle exception if FileStream does not exist catch( IOException ) { // notify user of error closing file MessageBox.Show( "Cannot close file", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } Application.Exit(); } // end method doneButton_Click } // end class CreditInquiryForm 26 Done button clicked event handler
27
CreditInquiry.cs Program Output 28
Random-Access Files Allows instant access to information Individual records can be accessed directly without searching through large numbers of other records Must be implemented through the application Easiest when all records are a fixed length Data can be inserted without destroying other data in file Records can be updated without rewriting the entire file Cannot serialize Won’t guarantee a fixed-length record size 29