.NET Streams Explained

by Wei-Meng Lee
04/14/2003

 

On of the common challenges facing beginning .NET programmers is the large number of classes in the .NET Class Library. Recently, I was working on a project involving file access. I was looking for the correct class to use for file handling and I realized that there are many classes in the System.IO namespace, each looking not much different from the others. And so, I set out to document some of the commonly used classes for performing regular file operations. The examples in the article are by no means exhaustive, but hopefully can help you in getting started with the right class!

Stream Class

A stream is an abstraction of a sequence of bytes. This sequence of bytes may come from a file, a TCP/IP socket, or memory. In .NET, a stream is represented, aptly, by the Stream class. The Stream class provides a generic view of a sequence of bytes. A Stream class forms the abstract class of all other streams. That is, you cannot directly create an instance of the Stream class. Instead, the Stream class is implemented by the following classes:

 

  1. BufferedStream: provides a buffering layer on another stream to improve performance.
  2. FileStream: provides a way to read and write files.
  3. MemoryStream: provides a stream using memory as the backing store.
  4. NetworkStream: provides a way to access data on the network.
  5. CryptoStream: provides a way to supply data for cryptographic transformation.

Streams fundamentally involve the following operations:

  1. Reading
  2. Writing
  3. Seeking

In this article, I will provide some examples to show the most commonly used classes for performing file I/O. In particular, I will use FileStream and MemoryStream, together with the File class for file creation, reading, and writing. I won’t be discussing each class in detail, as all of these details can be found from the excellent MSDN documentation that comes with Visual Studio .NET. Instead, I will just provide simple examples to illustrate the task that we are performing; the subheads of this article will be grouped by task.

All of the examples in this class make use of the following constants and variables:

 

Dim fs, s1, s2 As FileStream

Dim sr As StreamReader

Dim sw As StreamWriter

Dim br As BinaryReader

Dim bw As BinaryWriter

Dim ms As MemoryStream

 

Const FILE_NAME = "c:\textFile.txt"

Const BAK_FILE_NAME = "c:\textFile_bak.txt"

Const FILE_NAME_IMAGE = "c:\iMac.jpg"

Const FILE_NAME_BIN = "c:\bin.jpg"

Dim bytes(10) As Byte

 

Besides using FileStream and MemoryStream, I will also make use of the BinaryReader and BinaryWriter classes for reading and writing binary data, as well as the StreamReader and StreamWriter classes for reading and writing text data.

And since all of the classes discussed in this article fall under the System.IO namespace, I need to import it:

 

Imports System.IO

 

File Management

The File class allows you to create, delete, copy, and rename files. It also allows you to check if a file exists. The following example checks to see if a file exists, and if it does, makes a copy of the file and then deletes the original.

 

'---Copy and Delete the file

If File.Exists(FILE_NAME) Then

        File.Copy(FILE_NAME, BAK_FILE_NAME, True)

        File.Delete(FILE_NAME)

End If

 

File Creation

You can use the File class to create new files as well as open files for reading. The following example first creates a file and returns a FileStream object. It then creates a new text file and returns a StreamWriter object. Lastly, it illustrates that you can open a file for reading or writing using the Open() method from the File class.

 

fs = File.Create(FILE_NAME_BIN)

fs.Close()

 

sw = File.CreateText(FILE_NAME)

sw.Close()

 

fs = File.Open(FILE_NAME, FileMode.Open, FileAccess.Read, FileShare.Read)

fs.Close()

 

Writing Binary Data Using the FileStream Class

To write binary data to a file, you can use the FileStream class. The following example uses the FileStream class to create a new file for writing. It then writes 11 bytes to the file and closes it.

 

'---create a file and write some bytes to it

fs = New FileStream(FILE_NAME, FileMode.CreateNew, FileAccess.Write)

bytes(0) = 72 'H'

bytes(1) = 101 'e'

bytes(2) = 108 'l'

bytes(3) = 108 'l'

bytes(4) = 111 'o'

bytes(5) = 13 'CR'

bytes(6) = 87 'W'

bytes(7) = 111 'o'

bytes(8) = 114 'r'

bytes(9) = 108 'l'

bytes(10) = 100 'd'

 

fs.Write(bytes, 0, bytes.Length)

fs.Close()

 

Writing Text Using a StreamWriter Class

For writing text to a file, it is easier to use the StreamWriter class. The following example shows how to use the StreamWriter class to write a string of text to a file.

 

'---Using a streamWriter to write to a file

sw = New StreamWriter(FILE_NAME, True, System.Text.Encoding.ASCII)

sw.WriteLine("Welcome to VB.NET")

sw.Close()

 

Reading Binary Data Using the FileStream Class

To read binary data from a file, use the FileStream class. The following example opens a file and reads the binary data. The bytes read are then converted to ASCII characters and printed to the Output window.

 

'---open a file and read the byte(s) out

fs = New FileStream(FILE_NAME, FileMode.Open, FileAccess.Read)

fs.Read(bytes, 0, bytes.Length)

Dim i As Short

For i = 0 To bytes.Length - 1

               Console.Write(Chr(bytes(i)))

Next

 

Seeking

Stream objects can support seeking. The following example shows a FileStream object advancing 11 bytes and then starting to read the next six bytes.

 

'---seeking

fs.Seek(11, SeekOrigin.Current)

fs.Read(bytes, 0, 6)

For i = 0 To 5

               Console.Write(Chr(bytes(i)))

Next

fs.Close()

 

Reading Text Using the StreamReader Class

When reading text files, you can use the StreamReader class. The following example uses a StreamReader object to open a file for reading. The file is read line by line, and each line is printed to the Output window.

 

'---open a file and read line by line using a streamreader

sr = New StreamReader(FILE_NAME)

Dim line As String = sr.ReadLine()

 

While Not line Is Nothing

        Console.Write(line)

        line = sr.ReadLine()

End While

sr.Close()

 

Reading and Writing Binary Data Using the BinaryReader and BinaryWriter Classes

Besides using the FileStream class for reading and writing binary data, you can also use the BinaryReader and BinaryWriter classes. The following example reads the binary data from one file and writes it into another, essentially making a copy of the file. It first uses the FileStream class to open two files--one for reading and one for writing. The BinaryReader class is then used to read the binary data from the FileStream, and the BinaryWriter is used to write the binary data to the file.

 

'---read from and write to a binary file

s1 = New FileStream(FILE_NAME_IMAGE, FileMode.Open, FileAccess.Read)

s2 = New FileStream("c:\iMac_copy.jpg", FileMode.CreateNew, FileAccess.Write)

 

br = New BinaryReader(s1)

bw = New BinaryWriter(s2)

 

Dim byteRead As Byte

Dim j As Integer

For j = 0 To br.BaseStream.Length() - 1

        byteRead = br.ReadByte

        bw.Write(byteRead)

Next

br.Close()

bw.Close()

 

Writing Binary Data to a MemoryStream Class

Sometimes you need to load binary data from file and save it in memory for other uses. A good example is the PictureBox control in a Windows form. The following example shows how the BinaryReader class is used to read binary data from a file and then write it to a MemoryStream object. The PictureBox control then uses the data contained in the MemoryStream as a bitmap image.

 

'--read from a binary stream and write into a memory stream

s1 = New FileStream(FILE_NAME_IMAGE, FileMode.Open, FileAccess.Read)

ms = New MemoryStream(s1.Length)

br = New BinaryReader(s1)

Dim bytesRead As Byte() = br.ReadBytes(s1.Length)

ms.Write(bytesRead, 0, s1.Length)

PictureBox1.Image = New Bitmap(ms)

 

Some Useful Functions

Sometimes you may want to convert a string into a byte array, or vice versa, especially when you are using the Cryptographic APIs. I have provided three functions here to help you make the conversions. The three functions are:

  1. stringcharToByteArray(): converts a string of characters to a byte array.
  2. stringToByteArray(): converts a string of numbers into a byte array.
  3. byteArrayToString(): converts a byte array into a string.

 

Public Function stringcharToByteArray(ByVal str As String) As Byte()

        'e.g. "abcdefg" to {a,b,c,d,e,f,g}

        Dim s As Char()

        s = str.ToCharArray

        Dim b(s.Length - 1) As Byte

        Dim i As Integer

        For i = 0 To s.Length - 1

               b(i) = Convert.ToByte(s(i))

        Next

        Return b

End Function

 

Public Function stringToByteArray(ByVal str As String) As Byte()

        ' e.g. "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16" to

        '{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}

        Dim s As String()

        s = str.Split(" ")

        Dim b(s.Length - 1) As Byte

        Dim i As Integer

        For i = 0 To s.Length - 1

               b(i) = Convert.ToByte(s(i))

        Next

        Return b

End Function

 

Public Function byteArrayToString(ByVal b() As Byte) As String

        Dim i As Integer

        Dim s As New System.Text.StringBuilder()

        For i = 0 To b.Length - 1

               Console.WriteLine(b(i))

               If i <> b.Length - 1 Then

                       s.Append(b(i) & " ")

               Else

                       s.Append(b(i))

               End If

        Next

        Return s.ToString

End Function

 

Wei-Meng Lee , http://weimenglee.blogspot.com, is a technologist and founder of Developer Learning Solutions, a technology company specializing in hands-on training on the latest Microsoft technologies.