8.2 Readers and Writers

only for RuBoard

Although reading and writing directly to a stream is possible, working with an array of bytes can be difficult if the data in question is composed of integers, longs, doubles, or other primitive data typesor objects, for that matter. Fortunately, there are classes available (in System.IO ) whose sole purpose is to assist in reading and writing data to streams.

BinaryReader and BinaryWriter read and write primitive data types from a stream. There are also several readers and writers designed for character-based input and output, as opposed to "raw" bytes. These classes are derived from TextReader and TextWriter . Specifically, they are called StringReader/Writer and StreamReader/Writer .

8.2.1 BinaryReader and BinaryWriter

In Example 8-3, a file stream creates a stream to a file called data.bin . The stream instance constructs a BinaryWriter , which allows primitive data types to be written to the store.

Example 8-3. Using BinaryWriter
 Imports System Imports System.IO     Public Class StreamTest2         Public Sub New( )             Dim stream As New FileStream("data.bin", _                           FileMode.Create, _                           FileAccess.ReadWrite)             Dim writer As New BinaryWriter(stream)             Dim b As Byte = 1         Dim i As Integer = 2         Dim l As Long = 3         Dim d As Double = 3.1459         Dim s As String = "It's easy as ABC"             writer.Write(b)         writer.Write(i)         writer.Write(l)         writer.Write(d)         writer.Write(s)             writer.Close( )             Console.WriteLine("File written...")         End Sub     End Class     Public Class Application     Public Shared Sub Main( )         Dim test As New StreamTest2( )         Console.ReadLine( )     End Sub End Class 

After initializing a few variables with arbitrary values, the program writes them to the stream by using the BinaryWriter.Write method, which is overloaded for every type defined in the System namespace. The writer is then closed, and two things happen. The underlying stream is closed and the contents are written to the file.

The Read method isn't overloaded because there is no way to distinguish a byte with a value of 1 from an integer with a value of 1 . Instead, several Read datatype methods are defined for all the primitive types (including the non-CLS-compliant types). The following code, which reads back the data that was written to data.bin , illustrates the use of these Read... methods:

 Dim stream2 As New FileStream("data.bin", _                    FileMode.Open, _                    FileAccess.Read)     Dim reader As New BinaryReader(stream2)     b = reader.ReadByte( ) i = reader.ReadInt32( ) l = reader.ReadInt64( ) d = reader.ReadDouble( ) s = reader.ReadString( )     Console.WriteLine("{0} {1}, {2}, {3}, {4}", s, b, i, l, d)     reader.Close( ) 

One element of this code might not be straightforward. When the string is written to the file, the length of the string is encoded as an integer and placed before the string. This value is calculated 8-bits at a time, which is very efficient in terms of physical storage.

Example 8-4 contains the entire listing used to write to and read from data.bin .

Example 8-4. Using BinaryReader and BinaryWriter
 Imports System Imports System.IO     Public Class StreamTest2         Public Sub New( )             Dim stream As New FileStream("data.bin", _                           FileMode.Create, _                           FileAccess.ReadWrite)             Dim writer As New BinaryWriter(stream)             Dim b As Byte = 1         Dim i As Integer = 2         Dim l As Long = 3         Dim d As Double = 3.1459         Dim s As String = "It's easy as ABC"             writer.Write(b)         writer.Write(i)         writer.Write(l)         writer.Write(d)         writer.Write(s)             writer.Close( )             Console.WriteLine("File written...")             Console.WriteLine("Reading from file...")             Dim stream2 As New FileStream("data.bin", _                            FileMode.Open, _                            FileAccess.Read)             Dim reader As New BinaryReader(stream2)             b = reader.ReadByte( )         i = reader.ReadInt32( )         l = reader.ReadInt64( )         d = reader.ReadDouble( )         s = reader.ReadString( )             Console.WriteLine("{0} {1}, {2}, {3}, {4}", s, b, i, l, d)             reader.Close( )         End Sub     End Class     Public Class Application     Public Shared Sub Main( )         Dim test As New StreamTest2( )         Console.ReadLine( )     End Sub End Class 

8.2.2 StreamReader and StreamWriter

Earlier in this chapter, the System.Text.Encoding class was used to convert an array of bytes into a string. This example demonstrated how difficult it could be to work directly with a stream. While using Encoding like this works, a better alternative uses StreamReader . This class contains a Read method similar to that of Stream , but it returns characters instead of bytes.

What about StringReader ? It is not used for reading strings from a stream, but to stream data from a string. StringWriter , conversely, writes to a string.

Other Read methods simplify reading text-based input. StreamReader.ReadLine , shown here, reads from the stream until it finds a linefeed , a carriage return followed by a linefeed, or until it reaches the end of the stream. For example, the following code uses the StreamReader object's ReadLine method to read the single line of text from everything.txt :

 Dim stream As New FileStream("everything.txt", _                   FileMode.Open, _                   FileAccess.Read) Dim reader As New StreamReader(stream, Encoding.ASCII) Console.WriteLine(reader.ReadLine( )) reader.Close( ) 

A method called ReadToEnd can also be useful at times. It reads the stream from the current position all the way to the end and returns the result in a string.

The best performance, however, is realized by using the StreamReader class' Read method with an external buffer (shown in Example 8-5) that matches the size of the reader's internal buffer. By default, if a size is not specified, the internal buffer will be 4k. However, a 256-byte buffer works well with small amounts of data.

Example 8-5. High-performance stream access
 Imports System Imports System.IO Imports System.Text     Public Class StreamTest3         Public Sub New( )           Dim count As Integer         Dim buffer(256) As Char         Dim stream As New FileStream("everything.txt", _                           FileMode.Open, _                           FileAccess.Read)  Dim reader As New StreamReader(stream, _   Encoding.ASCII, _   False, _   buffer.Length)  count = reader.Read(buffer, 0, buffer.Length)         While count > 0             Console.WriteLine(buffer)             count = reader.Read(buffer, 0, buffer.Length)         End While         End Sub     End Class     Public Class Application     Public Shared Sub Main( )         Dim test As New StreamTest3( )         Console.ReadLine( )     End Sub End Class 

StreamWriter is not discussed here because it is merely the inverse of StreamReader . It contains an overloaded Write method just like BinaryWriter , as well as a WriteLine method, which writes to the stream just like Console.WriteLine writes to the console window. And speaking of the console ...

8.2.3 Console

The console uses a TextReader object to get input from the keyboard (known as the standard input stream), a TextWriter object to write to the screen (known as the standard output stream), and another TextWriter object to write to the standard error stream, which, by default, is the screen. Each object is available through the shared properties In , Out , and Error , respectively.

You can also redirect any of these streams by using SetIn , SetOut , and SetError . For instance, console input and output could be redirected to a file or a socket. Example 8-6 demonstrates redirection by sending standard output to a file. An exception is then intentionally generated and written to a file using Console.WriteLine . The original TextWriter used by the console is saved before output is redirected. After the exception is written to the file, it restores the console to its original state.

Example 8-6. Redirecting console output
 Imports System Imports System.IO     Public Class StreamTest4         Public Sub New( )         Dim stream As New FileStream("error.txt", _                           FileMode.OpenOrCreate, _                           FileAccess.Write)             Dim writer As New StreamWriter(stream)             'Save text writer         Dim oldWriter As TextWriter = Console.Out             'Set console output to error.txt         Console.SetOut(writer)             Try             'Divide by zero             Dim x As Long = 0             Dim y As Long = 8 \ x         Catch e As Exception             'Write to the error.txt             Console.WriteLine(e)         End Try             writer.Close( )             'Restore old text writer         Console.SetOut(oldWriter)         End Sub     End Class     Public Class Application     Public Shared Sub Main( )         Dim test As New StreamTest4( )         Console.WriteLine("Complete")         Console.ReadLine( )     End Sub End Class 

Multithreaded programming provides a real-world scenario for redirecting standard output. If several threads write to the console, the calls need to be synchronized; Console.WriteLine is not thread-safe. Output in these conditions will contain some garbage because multiple calls to Console.Write or WriteLine will step on each other.

To remedy this problem, TextWriter.Synchronized can place a thread-safe wrapper around the console TextWriter :

 Console.SetOut(TextWriter.Synchronized(Console.Out)) 
only for RuBoard


Object-Oriented Programming with Visual Basic. Net
Object-Oriented Programming with Visual Basic .NET
ISBN: 0596001460
EAN: 2147483647
Year: 2001
Pages: 112
Authors: J.P. Hamilton

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