Binary and text streams

2.2.3 Binary and text streams

When data contained in streams is of a well-known format, such as XML, plain text, or primitive types, there are methods available to greatly simplify the parsing of such data.

Plain text is most commonly used in streams that are designed to be human readable and editable. Plain-text streams exist in many network pro- tocols that were originally designed for text-only UNIX computers. A com- mon guise for plain-text files is the end-user modifiable application configuration files such as the ubiquitous .INI or .CSV; however, these are being somewhat replaced by XML in .NET.

A common feature of plain text is that each unit of information is termi- nated with an {enter} . This is actually a sequence of two UTF8 codes, 10 and 13 (represented in C# by \n and by VBCrLf in VB.NET). This can be tricky to parse out of a string, so methods such as ReadLine have been implemented in the textReader class.

To read a file one line at a time to the end, you could use code similar to the following application. Start a new project in Visual Studio .NET, and draw a button on the form. Name this button btnRead . Click on this but- ton, and enter the following code:

C#

private void btnRead_Click(object sender, System.EventArgs e) {

OpenFileDialog ofd = new OpenFileDialog(); ofd.ShowDialog(); FileStream fs = new FileStream(ofd.FileName, FileMode.OpenOrCreate); StreamReader sr = new StreamReader(fs); int lineCount=0; while (sr.ReadLine()!=null) {

lineCount++; } fs.Close(); MessageBox.Show("There are " + lineCount + " lines in " + ofd.FileName);

Chapter 2

30 2.2 Streams

VB.NET

Private Sub btnRead_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnRead.Click

Dim ofd As OpenFileDialog = New OpenFileDialog() ofd.ShowDialog() Dim fs As FileStream = New _

FileStream(ofd.FileName,FileMode.OpenOrCreate) Dim sr As StreamReader = New StreamReader(fs) Dim lineCount As Integer = 0 While Not sr.ReadLine() Is Nothing

lineCount = lineCount + 1 End While fs.Close() MessageBox.Show("There are " & lineCount & _

" lines in " & ofd.FileName) End sub

The following namespace must be included in the code in order for it to compile correctly:

C#

using System.IO;

VB.NET

Imports System.IO

To test the application, run it from Visual Studio .NET. Press the Read button, and then select a text file from the hard disk. Press OK, and a mes- sage box similar to Figure 2.2 will appear shortly.

When porting a .NET application from a console application to a Win- dows application, you will notice that the familiar format of the Con- sole.WriteLine method is not reflected in standard string handling. It is, however, available in StringBuilder.AppendFormat and Stream- Writer.WriteLine .

Not everything stored on disk or sent across a network has to be human readable. In many cases, significantly more efficient code can be written, which leverages the compact binary representations of variables. For instance, the number 65000 in a 16-bit unsigned Integer binary ( Uint16 ) is 11111101 11101000 (2 bytes); in text it is “6,” “5,” “0,” “0,” “0” (5 bytes).

2.2 Streams 31

Figure 2.2

Using streams to help read files.

Table 2.2 The significant methods and properties for StreamReader .

Method or Property Purpose

Constructor Initializes a new instance of the object. May be invoked thus: StreamReader(Stream).

Peek Returns the next available character, but does not consume it. Returns -1 at the end of a stream. Takes no parameters.

Read Reads the next character or next set of characters from the input stream. It may be invoked thus: Read(char[], int, int).

ReadBlock Reads characters from the current stream and writes the data to buffer, beginning at index. It may be invoked thus: ReadBlock(in char[] buffer, int index, int count).

ReadLine Reads a line of characters from the current stream and returns the data as a string. Takes no parameters; returns string.

ReadToEnd Reads the stream from the current position to the end of the stream. Takes no parameters; returns string.

To save an array of variables to disk, you could use the following applica- tion. Start a new project in Visual Studio .NET and draw a button on the form. Name this button btnWrite . Click on this button and enter the fol- lowing code:

C#

private void btnWrite_Click(object sender, System.EventArgs e)

SaveFileDialog sfd = new SaveFileDialog(); sfd.ShowDialog(); FileStream fs = new FileStream(sfd.FileName, FileMode.CreateNew);

Chapter 2

32 2.2 Streams

BinaryWriter bw = new BinaryWriter(fs); int[] myArray= new int[1000]; for(int i=0;i<1000;i++) {

myArray[i]=i; bw.Write(myArray[i]);

} bw.Close();

VB.NET

Private Sub btnWrite_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnRead.Click

Dim sfd As SaveFileDialog = New SaveFileDialog() sfd.ShowDialog() Dim fs As FileStream = New _ FileStream(sfd.FileName,FileMode.CreateNew) Dim bw As BinaryWriter = New BinaryWriter(fs) Dim myArray() As Integer = New Integer(1000) {} Dim i As Integer For i = 1 to 1000

myArray(i)=i bw.Write(myArray(i)) Next bw.Close()

End Sub

The following namespace must be included in the code in order for it to compile correctly:

C#

using System.IO;

VB.NET

Imports System.IO

To test the application, run it from Visual Studio .NET. Press the Write button and then select a location on the hard disk. Press OK, and a file will

be written to that location shortly.

2.2 Streams 33

Note: int in C# is a signed 4-byte number; thus the resultant file is exactly 4,000 bytes long.

The significant methods and properties for BinaryWriter are shown in Table 2.3.

Table 2.3 Significant members of the BinaryWriter class.

Method or Property

Purpose

Constructor Initializes a new instance of the object. May be invoked thus: BinaryWriter(Stream).

Close Closes the current BinaryWriter and the underlying stream. It takes no parameters.

Seek Sets the position within the current stream. It may be invoked thus: Seek(int offset, SeekOrigin origin).

Write Writes a value to the current stream. It may be invoked thus: Write(byte[]).

Write7BitEncodedInt Writes a 32-bit integer in a compressed format. It may be invoked thus: Write7BitEncodedInt(int value).