Click here to Skip to main content
Click here to Skip to main content

File Handling and Serialization in VB.NET

, 24 Sep 2007 CPOL
Rate this:
Please Sign up or sign in to vote.
This article explores the foundations of file handling and serialization in VB.NET

Introduction

.NET programs perform I/O through streams. A stream is an abstraction which either produces or consumes information. Alternatively, we can say that streams represent a sequence of bytes going to or coming from a storage medium (such as a file) or a physical or virtual device (network port or inter-process communication pipe). All streams behave in the same manner, even if the actual devices they are linked to may differ, which means we are going to use the same methods to write data to a standard output device as a disk file.

Byte Streams and Character Streams

At the lowest level, all I/O systems operate on bytes. In .NET, the char data type is of 2 Bytes to support the UNICODE character set. Using the ASCII character set it is easy to convert between char and byte by just ignoring the higher order byte. So we can not directly use byte streams to perform character based I/O. To overcome this problem .NET defines several classes that convert a byte stream to character stream, where handling of translation of byte-to-char and char-to-byte is automatic.

Predefined Steams

We have three predefined streams in .NET which can be redirected to any compatible I/O device.

  • Console.Out -> Represents the output stream associated with standard Output device.
  • Console.Err -> Represents the output stream associated with standard Error device.
  • Console.In -> Represents the input stream associated with standard Input device.

We have to import the required classes into our application for performing I/O operations.

  • Imports System.IO -> Namespace containing all I/O classes.
  • Stream Class -> This class represents a byte stream and is a base class for all other stream classes. As it is an abstract class we can instantiate it but it gives the information about a set of standard stream operations.
  • Close() -> Closes the stream.
  • Flush() -> Flushes the stream to push any data present in the stream to the destination.
  • ReadByte() -> Reads one byte of data from the input source and returns the integer representing that byte. If not successful it returns a value –1.
  • ReadBytes(Byte(),offset,noofbytes) -> Tries to read noofbytes of the input source and stores them in the byte array. It returns an integer stating how many bytes actually read.
  • Seek(offset,SeekOrigin) -> Moves the stream pointer to specific location of the stream.
  • WriteByte(Byte) -> Tries to write one byte to the output.
  • WriteBytes(Byte(),position,noofbytes) -> Tries to write noofbytes from the byte array starting from position to the output.

Exceptions

  • IOException: This exception is generated when an I/O operation fails.
  • NotSupportedException: This exception is generated when we attempt to perform an invalid operation not supported by the stream.

Before performing any operations through streams we can test for its support using CanRead(), CanSeek(), CanWrite() methods. We can also use the other properties as Length and Position for knowing the length and pointer position respectively.

Concept of Flush

When the file output is performed, data is often not immediately written to the actual physical device. Instead, the output is buffered by the O/S until a sizable chunk is obtained which is written all at once. If we can cause data to be written to the physical device whether the buffer is full or not we call the Flush() method, and this improves efficiency. Similarly, when we finished up writing to an output destination we should close the stream by using Close() which ensures data preset in buffer written to the physical device.

ByteStream Classes

  1. FileStream: This represents byte stream for File I/O.
  2. MemoryStream: Byte Stream that uses memory for storage.
  3. BufferedStream: Wraps a byte stream and adds buffering.

CharacterStreams Classes

To create a character stream we use the .NET character stream wrappers which wrap a byte stream within themselves. We can perform character based I/O using these character streams. The abstract classes in this category are TextReader and TextWriter.

Methods Supported by TextReader

  • ReadLine() -> Returns a string containing one line of data read from the input source.
  • Peek() -> Tries to see and know whether next character is available in the input stream or not. It returns –1 in case the next character is not available.
  • Read() -> Reads a character and returns –1 for non availability.
  • Read(Char(),position,noofchars)
  • ReadBlock(Char(),position,noofchars)
  • ReadToEnd() ->Returns a string containing data from current position to the end of input.

Methods supported by TextWriter

  • Write() -> This method has 16 overloads to support the writing of all data types.
  • WriteLine(String) -> Write the string as one line in the output.
  • Close() -> Closes the Writer.
  • Flush() -> Causes any data remaining in the output buffer to be written to the physical medium.

We will use classes like StreamReader, StreamWriter, StringReader and StringWriter.

BinaryStream Classes

These classes provide the functionality of reading and writing binary data directly.

FileStream: To create a byte stream linked to a file we use the file stream class. We can perform both read and write operations using this class.

'Constructor:
FileStream(String Filename,FileMode,FileAccess)

FileMode

  • Append: opens the file if it exists or creates a new file. Adds data to the end of the file.
  • Create: Will create a new file for writing, if it exists it will be overwritten.
  • CreateNew: Will create a new file, throws exception if the file already exists.
  • OpenOrCreate: Opens the file if exists or create the file.
  • Open: Opens the file reading or writing if exists or throws FileNotFoundException
  • Truncate: Opens the existing file and reduces its length to zero.

FileAccess

  • Read: Provides Read Access to the File.
  • Write: Provides Write Access to the File.
  • ReadWrite: Provides Read and write access to the file.

Example of FileStream

  1. Reading Data
Dim fs As FileStream = New
FileStream("a.txt", FileMode.Open, FileAccess.Read)
Dim i As Integer
Dim str As String = ""
i = fs.ReadByte()
While i <> -1
    str += Chr(i)
    i = fs.ReadByte()
End While
fs.Close()
TextBox1.Text = str
  1. Writing Data
Dim fs As FileStream = New
FileStream("a.txt", FileMode.Create, FileAccess.Write)
Dim arr() As Char =
TextBox1.Text.ToCharArray()
Dim c As Char
For Each c In arr
    fs.WriteByte(Asc(c))
Next
    fs.Close()

Using StreamReader and StreamWriter

  1. Reading Data
Dim fs As New
FileStream("stream.txt", FileMode.Open, FileAccess.Read)
Dim sreader As New StreamReader(fs)
Dim str As String
str = sreader.ReadLine()
While str <> ""
    TextBox1.Text += str + vbCrLf
    str = sreader.ReadLine()
End While
sreader.Close()
fs.Close()
  1. Writing Data
Dim fs As New
FileStream("stream.txt", FileMode.Create, FileAccess.Write)
Dim swriter As New StreamWriter(fs)
swriter.Write(TextBox1.Text)
swriter.Close()

BinaryReader and BinaryWriter

The BinaryReader and BinaryWriter classes are suitable for working with binary streams; one such stream might be associated with a file containing data in a native format. In this context, "native format" means the actual bits are used to store the value in memory. The data is read and written using its internal binary format, not its human readable text format. We must create a Stream object explicitly and pass it to the constructor method of either the BinaryReader or the BinaryWriter class. These classes provide a wrapper around the byte stream which manages the reading and writing of binary data.

Working with the BinaryWriter object is especially simple because its Write method is overloaded to accept all the primitive .NET types, including signed and unsigned integers; Single, Double, and String values; and so on.

The BinaryReader class exposes many Readxxxx methods, one for each possible native data type, and a PeekChar method that returns -1 at the end of the stream.

Outputting strings with a BinaryWriter requires some additional care, however. Passing a string to the Write method outputs a length-prefixed string to the stream. If you want to write only the actual characters (as often happens when you're working with fixed-length strings), you must pass the Write method an array of chars. The Write method is overloaded to take additional arguments that specify which portion of the array should be written. Reading back strings requires different techniques as well, depending on how the string was written. You use the ReadString method for length-prefixed strings and the ReadChars method for fixed-length strings.

Write Data Using BinaryStream

Dim fs As New
FileStream("binary.txt", FileMode.Create, FileAccess.Write)
Dim bwriter As New BinaryWriter(fs)
Dim x As Integer = 40
Dim c As Char = "A"
Dim f As Single = 23.45
bwriter.Write(x)
bwriter.Write(c)
bwriter.Write(f)
bwriter.Close()
fs.Close()

Read Data Using BinaryStream

Dim fs As New
FileStream("binary.txt", FileMode.Open, FileAccess.Read)
Dim breader As New BinaryReader(fs)
Dim a As Integer = breader.ReadInt32()
Dim t As Char = breader.ReadChar()
Dim s As Single = breader.ReadSingle()
TextBox1.Text = a & vbCrLf & t &
vbCrLf & s
breader.Close()
fs.Close()

Random Access Using Binary Stream

Dim fs as new
FileStream("binary.txt",FileMode.OpenOrCreate,FileAccess.Write)
Dim bwriter as new BinaryWriter(fs)
bwriter.BaseStream.Seek(0,SeekOrigin.End)
bwriter.Write("This is a
String")
bwriter.close()

Reading Data

Dim fs As New FileStream("binary.txt",
FileMode.OpenOrCreate, FileAccess.Read)
Dim breader As New BinaryReader(fs)
breader.BaseStream.Seek(0, SeekOrigin.Begin)
Dim a As Integer = breader.ReadInt32()
Dim t As Char = breader.ReadChar()
Dim s As Single = breader.ReadSingle()
Dim str As String = breader.ReadString()
TextBox1.Text = a & vbCrLf & t &
vbCrLf & s & vbCrLf & str
breader.Close()

Using VB.Net Runtime Functions

In addition to the I/O classes VB.NET supports some runtime functions which help us to perform the I/O operations on a file. Here we use a File Number which is an integer value representing the file in memory and this number is used to perform operations on that file.

It exposes functions like:

  1. FileOpen(FileNumber,String filename,OpenMode) -> Opens the named file in the OpenMode specified and it is identified with FileNumber. The mode can be OpenMode.Output, OpenMode.Append, OpenMode.Input, OpenMode.Binary.
  2. PrintLine(FileNumber,String) -> Writes the string as a line to the file represented by FN.

  3. FileClose(FileNumber) -> Closes the File.
  4. LineInput(FileNumber) -> returns a string by reading one line from the file.
  5. EOF(FileNumber) -> States True/False informing whether end of file is reached.
  6. FilePut(FileNumber,Object) -> Writes data to the file including objects and structures.
  7. FileGet(FileNumber,object) -> Tries to read native data from the file.
  8. InputString(FileNmber,noofchars) -> Returns a string by reading characters from the file

Writing Data

FileOpen(10, "myfile.txt", OpenMode.Output)
PrintLine(10, TextBox1.Text)
FileClose(10)
MsgBox("Data Saved")

Reading Data

FileOpen(78, "myfile.txt", OpenMode.Input)
While Not EOF(78)
TextBox1.Text += LineInput(78) & vbCrLf
End While
FileClose(78)

Using Structures

Structure student
Dim roll As Integer
Dim nm As String
Public Sub New(ByVal r As Integer, ByVal n As String)
    roll = r
    nm = n
End Sub
Public Sub display()
    MsgBox("The values are " & roll & Space(5) & nm)
End Sub
End Structure

Writing Structures

Dim s1 As New student(10, "Ashok")
FileOpen(10, "struct.txt", OpenMode.Binary)
FilePut(10, s1)
FileClose(10)
MsgBox("Structure saved")

Reading Structures

Dim s2 As New student
FileOpen(100, "struct.txt", OpenMode.Binary)
FileGet(100, s2)
s2.display()
FileClose(100)

Object Persistence or Serialization

Serialization is the term for the act of saving (or serializing) an object onto a storage Medium — a file, a database field, a buffer in memory — and later deserializing it from the storage medium to re-create an object instance that can be considered identical to the original one. Serialization is a key feature in the .NET Framework and is transparently used by the runtime for tasks other than simply saving an object to a file. For example, marshaling an object by value to another application. You should make an object serializable if you plan to send it to another application or save it on disk or in a database field by setting the <Serializable()> attribute in the class definition.

Serialization and persistence are often used as synonyms, so you can also say that an object is persisted and depersisted. The MSDN documentation makes a distinction, however, and uses persistence to mean that the data is stored in a durable medium, such as a file or a database field, while serialization can be applied to objects stored in nondurable media, such as memory buffers.

The .NET Framework knows how to serialize all basic data types, including numbers, strings, and arrays of numbers and strings, so you can save and reload these types to and from a file stream (or any other type of stream) with minimal effort. All we need to serialize and deserialize a basic object is the use of a proper formatter object. Formally speaking, a formatter is an object that implements the IFormatter interface (defined in the System.Runtime.Serialization namespace).

  1. The BinaryFormatter object, defined in System.Runtime.Serialization.Formatters. Binary namespace, provides an efficient way to persist an object in a compact binary format. In practice, the actual bits in memory are persisted, so the serialization and deserialization processes are very fast.
  2. The SoapFormatter object, defined in System.Runtime.Serialization.Formatters. SOAP namespace, persists data in human-readable XML format, following the Simple Object Access Protocol (SOAP) specifications. The serialization and deserialization processes are somewhat slower than with the BinaryFormatter object. On the other hand, data can be sent easily to another application through HTTP and displayed in a human-readable format.

Binary Serialization

The key methods that all formatter objects support are Serialize and Deserialize, whose purpose is rather evident. The Serialize method takes a Stream object as its first argument and the object to be serialized as its second argument:

'Create an array of integers.
Dim arr() As Integer = {1, 2, 4, 8, 16, 32, 64, 128, 256}
' Open a file stream for output.             
Dim fs As FileStream = New FileStream("ser.dat", FileMode.Create)
' Create a binary formatter for this stream.
Dim bf As New BinaryFormatter()
' Serialize the array to the file stream, and flush the stream.
bf.Serialize(fs, arr)
fs.Close()

Reading back the file data and deserializing it into an object requires the Deserialize function, which takes the input Stream as its only argument and returns an Object value, which must be cast to a properly typed variable:

'Open a file stream for input.
Dim fs As FileStream = New FileStream("ser.dat", FileMode.Open)
' Create a binary formatter for this stream.
Dim bf As New BinaryFormatter()
' Deserialize the contents of the file stream into an Integer array.
' Deserialize returns an object that must be coerced.
Dim arr() As Integer = CType(bf.Deserialize(fs), Integer())
' Display the result.
For Each n As Integer In arr
    Console.Write(n.ToString & " ")
Next

SOAP Serialization

You can change the serialization format to SOAP by simply using another formatter object, the SoapFormatter. This namespace isn't available in the default Visual Basic console project, so you have to click Add Reference on the Project menu in Visual Studio to add the System.Runtime.Serialization.Formatters.Soap.dll library to the list of libraries that appears in the Object Browser. Note that the SoapFormatter's constructor is passed a StreamingContext object that specifies where the serialization data is stored:

' Serialize an object to a file in SOAP format.
Sub SaveSoapData(ByVal o As Object)
' Open a file stream for output.
Dim fs As FileStream = New FileStream("soap.xml", FileMode.Create)
' Create a SOAP formatter for this file stream.
Dim sf As New SoapFormatter(Nothing, New StreamingContext(
    StreamingContextStates.File))
' Serialize the array to the file stream, and close the stream.
sf.Serialize(fs, o)
fs.Close()
End Sub

' Deserialize an object from a file in SOAP format.
Function LoadSoapData() As Object
' Open a file stream for input.
Dim fs As FileStream = New FileStream("soap.xml", FileMode.Open)
' Create a SOAP formatter for this file stream.
Dim sf As New SoapFormatter(Nothing, 
    New StreamingContext(StreamingContextStates.File))
' Deserialize the contents of the stream into an object and close the stream.
LoadSoapData = sf.Deserialize(fs)
fs.Close()
End Function

To make a user-defined class Serializable we have to use <Serializable()> attribute for a class as:

<Serializable()> Class SerClass
Public x,y as Integer
Public Sub New()
x=10
y=20
End Sub
End Class

To Serialize

Dim fs As FileStream = New FileStream("obj.dat", FileMode.Create)
Dim bf As New BinaryFormatter()
' Serialize the class to the file stream, and flush the stream.
bf.Serialize(fs, New SerClass())
fs.Close()

To Deserialize

Dim fs As FileStream = New FileStream("obj.dat", FileMode.Open)
Dim bf As New BinaryFormatter()
' Deserialize the contents of the file stream into an Integer array.
' Deserialize returns an object that must be coerced.
Dim o As SerClass = CType(bf.Deserialize(fs), SerClass)
MsgBox(o.x & Space(5) & o.y)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author


Comments and Discussions

 
GeneralMy vote of 4 PinmemberVitorHugoGarcia5-Mar-13 22:12 
GeneralMy vote of 5 PinmemberJαved26-Mar-12 22:16 
GeneralThank you VERY much!!! PinmemberBruceL12-Apr-11 6:34 
GeneralMy vote of 5 PinmemberBruceL12-Apr-11 6:30 
GeneralSOAP doesn't work with generics PinmemberPi210-Apr-09 3:09 
GeneralStreaming on excel file... Pinmemberguntupalli_hanu22-Dec-08 23:18 
Questionproblem in accessing a folder Pinmemberchitzquest30-Jun-08 18:44 
AnswerRe: problem in accessing a folder PinmemberAKPatra6-Jul-08 23:15 
Generalserialisation PinmemberUmberto-Italy8-Oct-07 3:59 
QuestionHard-coded FileNumber field - why? Pinmemberscottb23-Oct-07 8:28 
AnswerRe: Hard-coded FileNumber field - why? PinmemberAKPatra3-Oct-07 16:12 
GeneralRe: Hard-coded FileNumber field - why? Pinmemberscottb23-Oct-07 22:00 
GeneralGood Article, now understand the serializacion PinmemberZuluPapa1-Oct-07 12:54 

Wonderful summary, very material, with a level of english simple and with examples concise and practical.
 
Thanks AKPatra Smile | :)

GeneralExcellent article PinmemberKennethNilsen1-Oct-07 7:30 
GeneralRe: Help about process "text file" PinmemberAKPatra28-Sep-07 18:58 
General[Message Deleted] PinmemberBomy29-Sep-07 21:58 
GeneralRe: Help about process &quot;text file&quot; PinmemberAKPatra30-Sep-07 16:50 
GeneralRe: Help about process &quot;text file&quot; PinmemberAKPatra30-Sep-07 16:56 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.141022.2 | Last Updated 24 Sep 2007
Article Copyright 2007 by AshokPatra
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid