FileStream and Byte-Oriented File IO


FileStream and Byte-Oriented File I/O

C# provides classes that allow you to read and write files. Of course, the most common type of files are disk files. At the operating system level, all files are byte oriented. As you would expect, C# provides methods to read and write bytes from and to a file. Thus, reading and writing files using byte streams is very common. C# also allows you to wrap a byte-oriented file stream within a character-based object. Character-based file operations are useful when text is being stored. Character streams are discussed later in this chapter. Byte-oriented I/O is described here.

To create a byte-oriented stream attached to a file, you will use the FileStream class. FileStream is derived from Stream and contains all of Stream’s functionality.

Remember, the stream classes, including FileStream, are defined in System.IO. Thus, you will usually include

 using System.IO;

near the top of any program that uses them.

Opening and Closing a File

To create a byte stream linked to a file, create a FileStream object. FileStream defines several constructors. Perhaps its most commonly used one is shown here:

 FileStream(string filename, FileMode mode)

Here, filename specifies the name of the file to open, which can include a full path specification. The mode parameter specifies how the file will be opened. It must be one of the values defined by the FileMode enumeration. These values are shown in Table 14-4. This constructor opens a file for read/write access.

Table 14-4: The FileMode Values

Value

Description

FileMode.Append

Output is appended to the end of file.

FileMode.Create

Creates a new output file. Any preexisting file by the same name will be destroyed.

FileMode.CreateNew

Creates a new output file. The file must not already exist.

FileMode.Open

Opens a preexisting file.

FileMode.OpenOrCreate

Opens a file if it exists, or creates the file if it does not already exist.

FileMode.Truncate

Opens a preexisting file, but reduces its length to zero.

If a failure occurs when attempting to open the file, an exception will be thrown. If the file cannot be opened because it does not exist, FileNotFoundException will be thrown. If the file cannot be opened because of an I/O error, IOException will be thrown. Other possible exceptions are ArgumentNullException (the filename is null), ArgumentException (the filename is invalid), SecurityException (user does not have access rights), DirectoryNotFoundException (specified directory is invalid), PathTooLongException (the filename/path is too long), and ArgumentOutOfRangeException (mode is invalid).

The following shows one way to open the file test.dat for input:

 FileStream fin; try {   fin = new FileStream("test.dat", FileMode.Open); } catch(FileNotFoundException exc) {   Console.WriteLine(exc.Message);   return; } catch {   Console.WriteLine("Cannot open file.");   return; }

Here, the first catch clause catches the file-not-found error. The second catch, which is a “catch all” clause, handles the other possible file errors. You could also check for each error individually, reporting more specifically the problem that occurred. For the sake of simplicity, the examples in this book will catch only FileNotFoundException or IOException, but your real-world code may need to handle the other possible exceptions, depending upon the circumstances.

As mentioned, the FileStream constructor just described opens a file that has read/ write access. If you want to restrict access to just reading or just writing, use this constructor instead:

 FileStream(string fi lename, FileMode mode, FileAccess how)

As before, filename specifies the name of the file to open, and mode specifies how the file will be opened. The value passed in how determines how the file can be accessed. It must be one of the values defined by the FileAccess enumeration, which are shown here:

FileAccess.Read

FileAccess.Write

FileAccess.ReadWrite

For example, this opens a read-only file:

 FileStream fin = new FileStream("test.dat", FileMode.Open, FileAccess.Read);

When you are done with a file, you should close it by calling Close( ). Its general form is shown here:

 void Close( )

Closing a file releases the system resources allocated to the file, allowing them to be used by another file. Close( ) can throw an IOException.

Reading Bytes from a FileStream

FileStream defines two methods that read bytes from a file: ReadByte( ) and Read( ). To read a single byte from a file, use ReadByte( ), whose general form is shown here:

 int ReadByte( )

Each time it is called, it reads a single byte from the file and returns it as an integer value. It returns 1 when the end of the file is encountered. Possible exceptions include NotSupportedException (the stream is not opened for input) and ObjectDisposedException (the stream is closed).

To read a block of bytes, use Read( ), which has this general form:

 int Read(byte[ ] buf, int offset, int numBytes) 

Read( ) attempts to read up to numBytes bytes into buf starting at buf[offset]. It returns the number of bytes successfully read. An IOException is thrown if an I/O error occurs. Several other types of exceptions are possible, including NotSupportedException, which is thrown if reading is not supported by the stream.

The following program uses ReadByte( ) to input and display the contents of a text file, the name of which is specified as a command-line argument. Note the try/catch blocks that handle two errors that might occur when this program is first executed: the specified file not being found or the user forgetting to include the name of the file. You can use this same approach any time you use command-line arguments.

 /* Display a text file.    To use this program, specify the name    of the file that you want to see.    For example, to see a file called TEST.CS,    use the following command line.    ShowFile TEST.CS */ using System; using System.IO; class ShowFile {   public static void Main(string[] args) {     int i;     FileStream fin;     try {       fin = new FileStream(args[0], FileMode.Open);     } catch(FileNotFoundException exc) {       Console.WriteLine(exc.Message);       return;     } catch(IndexOutOfRangeException exc) {       Console.WriteLine(exc.Message + "\nUsage: ShowFile File");       return;     }     // read bytes until EOF is encountered     do {       try {         i = fin.ReadByte();       } catch(Exception exc) {         Console.WriteLine(exc.Message);         return;       }       if(i != -1) Console.Write((char) i);     } while(i != -1);     fin.Close();   } }

Writing to a File

To write a byte to a file, use the WriteByte( ) method. Its simplest form is shown here:

 void WriteByte(byte val)

This method writes the byte specified by val to the file. If an error occurs during writing, an IOException is thrown. If the underlying stream is not opened for output, a NotSupportedException is thrown. If the stream is closed, ObjectDisposedException is thrown.

 You can write an array of bytes to a file by calling Write( ). It is shown here: void Write(byte[ ] buf, int offset, int numBytes)

Write( ) writes numBytes bytes from the array buf, beginning at buf[offset], to the file. If an error occurs during writing, an IOException is thrown. If the underlying stream is not opened for output, a NotSupportedException is thrown. Several other exceptions are also possible.

As you may know, when file output is performed, often that output is not immediately written to the actual physical device. Instead, output is buffered by the operating system until a sizable chunk of data can be written all at once. This improves the efficiency of the system. For example, disk files are organized by sectors, which might be anywhere from 128 bytes long, on up. Output is usually buffered until an entire sector can be written all at once. However, if you want to cause data to be written to the physical device whether the buffer is full or not, you can call Flush( ), shown here:

 void Flush( )

An IOException is thrown on failure. If the stream is closed, ObjectDisposedException is thrown.

Once you are done with an output file, you must remember to close it using Close( ). Doing so ensures that any output remaining in a disk buffer is actually written to the disk. Thus, there is no reason to call Flush( ) before closing a file.

Here is a simple example that writes to a file:

 // Write to a file. using System; using System.IO; class WriteToFile {   public static void Main(string[] args) {     FileStream fout;     // open output file     try {       fout = new FileStream("test.txt", FileMode.Create);     } catch(IOException exc) {       Console.WriteLine(exc.Message + "\nError Opening Output File");       return;     }     // Write the alphabet to the file.     try {       for(char c = 'A'; c <= 'Z'; c++)         fout.WriteByte((byte) c);     } catch(IOException exc) {       Console.WriteLine(exc.Message + "File Error");     }     fout.Close();   } }

The program first opens a file called test.txt for output. It then writes the uppercase alphabet to the file. Finally, it closes the file. Notice how possible errors are handled by the try/catch blocks. After this program executes, test.txt will contain the following output:

 ABCDEFGHIJKLMNOPQRSTUVWXYZ

Using FileStream to Copy a File

One advantage to the byte-oriented I/O used by FileStream is that you can use it on any type of file—not just those that contain text. For example, the following program copies any type of file, including executable files. The names of the source and destination files are specified on the command line.

 /* Copy a file.    To use this program, specify the name    of the source file and the destination file.    For example, to copy a file called FIRST.DAT    to a file called SECOND.DAT, use the following    command line.    CopyFile FIRST.DAT SECOND.DAT */ using System; using System.IO; class CopyFile {   public static void Main(string[] args) {     int i;     FileStream fin;     FileStream fout;     try {       // open input file       try {         fin = new FileStream(args[0], FileMode.Open);       } catch(FileNotFoundException exc) {         Console.WriteLine(exc.Message + "\nInput File Not Found");         return;       }       // open output file       try {         fout = new FileStream(args[1], FileMode.Create);       } catch(IOException exc) {         Console.WriteLine(exc.Message + "\nError Opening Output File");         return;       }     } catch(IndexOutOfRangeException exc) {       Console.WriteLine(exc.Message + "\nUsage: CopyFile From To");       return;     }     // Copy File     try {       do {         i = fin.ReadByte();         if(i != -1) fout.WriteByte((byte)i);       } while(i != -1);     } catch(IOException exc) {       Console.WriteLine(exc.Message + "File Error");     }     fin.Close();     fout.Close();   } }




C# 2.0(c) The Complete Reference
C# 2.0: The Complete Reference (Complete Reference Series)
ISBN: 0072262095
EAN: 2147483647
Year: 2006
Pages: 300

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net