Page 1 of 1

Part I - System.IO in VB.Net Rate Topic: -----

#1 PsychoCoder  Icon User is offline

  • Google.Sucks.Init(true);
  • member icon

Reputation: 1642
  • View blog
  • Posts: 19,853
  • Joined: 26-July 07

Posted 27 December 2007 - 09:40 PM

In this Part 1 of my tutorial series on working with the System.IO Namespace with VB.Net, we will take a look at working with the System.IO Namespace in VB.Net to do various manipulations on text files, then in Part II we'll get into file conversions, such as converting a delimited file into an XML Document and so on..All of these are members of the System.IO Namespace, which contains objects and classes for reading from and writing to data streams, they also provide file and directory functionality.

A lot of this code will look similar to the tutorial I wrote on the same topic in C#, but I have optimized the majority of the code (I do that a lot when reading code Ive already written), and have introduced working with Structures in VB.Net. Throwing this into the mis has allowed me to remove 3 functions from the class, thus optimizing it even further.

In this tutorial we will start with the basic file and directory operations such as reading from a text file, writing to a
text file, and checking if a file exists before working with it. In part II we will then look at more intermediate processes such as creating a directory, converting a comma delimited file to an XML document, copying and deleting both a single file and all the files in a directory, and how to access file Properties such as ReadOnly status and Last Access time.

The first thing we need to add to our class, as with any class we write, are the Namespaces we will need. Once new one from the C# version of this Class Library is using the System.Collections.Generic Namespace, as we will be introducing working with a Generic list that is of the type of our structure we'll be looking at later. First the Namespaces:

Imports System
Imports System.IO
Imports System.Data.SqlClient
Imports System.Collections
Imports System.Collections.Generic
Imports System.Collections.ObjectModel



Earlier I mentiond the addition of a Structure, which is like a class, but is normally used for grouping like data members (types of cars, file attributes, etc). The Structure Ive introduced allowed me to remove all the Functions used to retrieve certain file attributes, now I can do it in a single function and return the results in a Generic List(Of T):

#Region " Structures "
	''' <summary>
	''' Structure to hold various file attributes
	''' </summary>
	''' <remarks></remarks>
	Structure FileInformation
		Public ReadOnlyStatus As Boolean
		Public HiddenStatus As Boolean
		Public FileSize As Double
		Public LastAccess As DateTime
		Public FileCreatedOn As DateTime
		Public LastWrite As DateTime
		Public Name As String
		Public FileExtension As String
		Public FileLocation As String
	End Structure
#End Region



Another thing I did to try and improve the performance and scalability of this Class Library is by introducing Properties, thus allowing the end user to not have to pass all information in the signature of a method (such as file name, directory, etc). As you know, Properties need private variables to populate them, making them private means their values cannot be altered outside the class. So now for the Properties for this Class Library:

#Region " Variables "
	Dim _fileName As String
	Dim _directoryName As String
	Dim _conversionValue As Integer
	Dim _conversionType As String
	Dim _fileSize As Double
	Dim _textToWrite As String
	Dim _status As Boolean
	Dim _returnMessage As String
#End Region

#Region " Properties "
	Public Property FileName() As String
		Get
			Return _fileName
		End Get
		Set(ByVal value As String)
			_fileName = value
		End Set
	End Property

	Public Property DirectoryName() As String
		Get
			Return _directoryName
		End Get
		Set(ByVal value As String)
			_directoryName = value
		End Set
	End Property

	Private ReadOnly Property ConversionMultiplier()
		Get
			_conversionValue = 1024
			Return _conversionValue
		End Get
	End Property

	Public Property ConversionType() As String
		Get
			Return _conversionType
		End Get
		Set(ByVal value As String)
			_conversionType = value
		End Set
	End Property

	Public ReadOnly Property FileSize() As Double
		Get
			Return _fileSize
		End Get
	End Property

	Public Property TextToWrite() As String
		Get
			Return _textToWrite
		End Get
		Set(ByVal value As String)
			_textToWrite = value
		End Set
	End Property

	Public ReadOnly Property Status() As Boolean
		Get
			Return _status
		End Get
	End Property

	Public ReadOnly Property ReturnMessage()
		Get
			Return _returnMessage
		End Get
	End Property
#End Region



The first set of actions we will be looking at is reading and writing to a text file. The first of these is the simplest, simply writing some text to a file. Here we will create a TextWriter to create the file, then open it with a StreamWriter, then we will use the WriteLine Method to write the text to the file:

#Region " WriteToFile "
	''' <summary>
	''' Method for writing to a file
	''' </summary>
	Public Sub WriteToFile()
		'always use a try...catch to deal 
		'with any exceptions that may occur
		Try
			'create a TextWriter then open the file
			Using writer As TextWriter = New StreamWriter(_fileName)
				'now write the message to the file
				writer.WriteLine(_textToWrite)
			End Using
		Catch ex As Exception
			'deal with any errors
			_returnMessage = ex.Message
		End Try

	End Sub
#End Region



Here we create an instance of the StreamReader class to open the file. We then use the Write Method to write our text to the file. The variable _textToWrite is the Property set in the calling method or application. In the above method we are introduced to 2 of the TextWriter Members:The main difference between the two is WriteLine adds a line terminator to the end of the line, whereas Bb]Write[/b] you have to explicitly write one. Next we will look at writing to a specified line in an existing file, say like 5, but to do this you first much make sure the file you're writing to has at least 5 lines, otherwise you get an ArgumentOutOfRangeException, as you'll be trying to write to a line that doesnt exist:

#Region " WriteToSpecifiedLine "
	''' <summary>
	''' Method for writing text to a specified line
	''' </summary>
	''' <param name="line">Line to insert text</param>
	Public Sub WriteToSpecifiedLine(ByVal line As Integer)
		'always use a try...catch to deal 
		'with any exceptions that may occur
		Try
			'make sure the file actually exists
			'if not create and open it
			If Not System.IO.File.Exists(_fileName) Then
				System.IO.File.Create(_fileName)
			End If
			'open the file
			Using reader As New StreamReader(_fileName)
				'get the contents of the file
				Dim contents As String = reader.ReadToEnd()
				'insert the specified line
				contents.Insert(line, _textToWrite)
				'now we need to rewrite the text in the file
				Using writer As New StreamWriter(_fileName, False)
					'write the file with the new line
					writer.Write(contents)
				End Using
			End Using
		Catch ex As Exception
			'deal with any errors
			_returnMessage = ex.Message
		End Try
	End Sub
#End Region



For reading from a text file, lets start with something simple, say reading the first line we come to. Here we will open the file the same way we did when we first wrote to the file, except here we use ReadLine to read a single line from the file, generally the first line in the file, then return that to the calling method:

#Region " ReadSingleLine "
	''' <summary>
	''' Method for reading a single line in a file
	''' </summary>
	''' <returns>The text in that line</returns>
	Public Function ReadSingleLine() As String
		'create a variable to hold our line
		Dim lineText As String = String.Empty
		'always use a try...catch to deal 
		'with any exceptions that may occur
		Try
			'create a new TextReader then open the file
			Using reader As TextReader = New StreamReader(_fileName)
				'read a single line from the file
				lineText = reader.ReadLine()
			End Using
		Catch ex As FileNotFoundException
			lineText = String.Empty
			_returnMessage = ex.Message
		Catch ex As Exception
			'deal with any errors
			_returnMessage = ex.Message
			lineText = String.Empty
		End Try
		Return lineText
	End Function
#End Region



Next we will take a look at reading from a text file. We will examine 2 different ways to accomplish this, we will loop through the file, reading a line at a time and adding it to our string variable, then we will read the whole file at once, adding it to our variable. In these examples we are introduced to the TextReader Class. First, the read a line at a time example:

#Region " ReadFileByLine "
	''' <summary>
	''' Method for reading a text _fileName a line at a time
	''' and adding it to a string to return to calling method
	''' </summary>
	''' <returns>_fileName contents in a string</returns>
	Public Function ReadFileByLine() As String
		'create a string variable to hold the file contents
		Dim contents As String = String.Empty
		'always use a try...catch to deal 
		'with any exceptions that may occur
		Try
			'create a new TextReader then open the file
			Using reader As TextReader = New StreamReader(_fileName)
				'loop through the entire file
				While reader.Peek() <> -1
					'add each line to the contents variable
					contents += reader.ReadLine().ToString()
				End While
			End Using
		Catch ex As FileNotFoundException
			contents = String.Empty
			_returnMessage = ex.Message
		Catch ex As Exception
			'deal with any errors
			_returnMessage = ex.Message
			contents = String.Empty
		End Try
		'return the results
		Return contents
	End Function
#End Region



NOTE: You will notice that I put all my code into #Region ... #End Region blocks, this allows me to easily separate any class or file into seperate regions, also making it easier to find certain code faster if I know which region it is in.

In this example we created a string variable contents to hold the contents of the file, we then loop through the file a line at a time adding each line to the contents variable. Here we are introduced to 2 of the TextReader Members:Peek is used to determine when we are at the end of the file, as long as it isn't returning -1 then there is more data in the file. Inside the loop we use ReadLine to read each line individually, then appending it to the
variable.

There are 3 more Members of the TextReader Class other than the ReadLine mentioned above. They are:Next to ReadLine, ReadToEnd is the most commonly used method of the TextReader Class. As the name implies, it reads the entire file at once, no need to use Peek or a loop. Lets take a look at an example employing this member:

#Region " ReadEntireFile "
	''' <summary>
	''' Method for reading an entire _fileName at once
	''' </summary>
	''' <returns>_fileName contents in a string</returns>
	Public Function ReadEntireFile() As String
		'create a string variable to hold the contents of the file
		Dim contents As String = String.Empty
		'always use a try...catch to deal 
		'with any exceptions that may occur
		Try
			'create a new TextReader and open our file
			Using reader As TextReader = New StreamReader(_fileName)
				'now read the entire file at once into our variable
				contents = reader.ReadToEnd().ToString()
			End Using
			_status = True
		Catch ex As FileNotFoundException
			_status = False
			contents = String.Empty
			_returnMessage = ex.Message
		Catch ex As Exception
			_status = False
			'deal with any errors
			_returnMessage = ex.Message
			contents = String.Empty
		End Try
		Return contents
	End Function
#End Region



As in the previous example, we create our string variable contents to hold the contents of the file, we create our TextReader object using the Using Statement, but unlike before, we don't use a loop. In this example we use ReadToEnd to read the entire file on one pass. Both approaches, as with any programming approach, have their pro's and con's.

NOTE: Always put your logic inside a Try...Catch block to catch and deal with any Exceptions that may have been raised during the process. Try to not always use Catch ex As Exception as your only catch. Since you're writing the code you should have a small idea on what exceptions can occur in your code. Using the generic Exception in the final Catch is fine.

In the next example, lets look at reading from a specified line in a text file. In this example, we split the lines in the file into an array, this allows us to know beforehand if this particular file has the number of lines the user is looking for, thus preventing receiving an ArgumentOutOfRangeException. Then the user can pass an integer value representing which line they'd like to read.

#Region " ReadSpecifiedLine "
	''' <summary>
	''' Method to read a specified line in a text file
	''' </summary>
	''' <param name="line">Line number to read</param>
	''' <returns></returns>
	Public Function ReadSpecifiedLine(ByVal line As Integer) As String
		'create a variable to hold the contents of the file
		Dim contents As String = String.Empty
		'create a variable to hold our line contents
		Dim lineText As String = String.Empty
		' always use a try...catch to deal 
		' with any exceptions that may occur
		Try
		   
			'thanks for the idea from RodgerB at </dream.in.code>
			Using lineByLine As New IO.StreamReader(_fileName)
				Dim lineCount As Integer = 0
				While Not lineByLine.EndOfStream
					lineByLine.ReadLine()
					If lineCount = line Then
						lineText = lineByLine.ReadLine()
					End If
					lineCount += 1
				End While
			End Using
		Catch ex As FileNotFoundException
			lineText = String.Empty
			_returnMessage = ex.Message
		Catch ex As Exception
			' deal with any errors
			_returnMessage = ex.Message
		End Try
		Return lineText
	End Function
#End Region

As with the previous examples we create the string variable [b]contents[/b], our [b]StreamReader[/b] Object, the difference here is we, as stated above, convert the lines in the file into a string array, then use the value passed by the user to read that specified line (using the value as the index of the array) and set the value of our variable to that line's value.

Lets take a look at once final Member of the [b]System.IO.File[/b] Class, the [url=http://msdn2.microsoft.com/en-us/library/system.io.file.exists.aspx]Exists Member[/url]. This member allows us to check if the specified file exists prior to opening and manipulating it.

[code]
#Region " ReadEntireFileIfExists "
	''' <summary>
	''' Method for reading a file if it exists
	''' </summary>
	''' <returns>_fileName contents in a string</returns>
	Public Function ReadEntireFileIfExists() As String
		'create a string variable to hold the contents of the file
		Dim contents As String = String.Empty
		'always use a try...catch to deal 
		'with any exceptions that may occur
		Try
			'check to see if the file exists
			If System.IO.File.Exists(_fileName) Then
				'create a new TextReader and open our file
				Using reader As TextReader = New StreamReader(_fileName)
					'now read the entire file at once into our variable
					contents = reader.ReadToEnd()
				End Using
				_status = True
			Else
				_status = False
				Throw New FileNotFoundException(_fileName + " could not be found")
			End If
		Catch ex As FileNotFoundException
			'handle your errors here
			_status = False
			_returnMessage = ex.Message
			contents = String.Empty
		Catch ex As Exception
			'handle your errors here
			_status = False
			_returnMessage = ex.Message
			contents = String.Empty
		End Try
		Return contents
	End Function
#End Region



Notice we use Exists to determine if the file actually exists prior to using it. If the file exists we go ahead and read the file, if the file doesn't exist we throw a [b/FileNotFoundException[/b] letting the user know the file doesn't exist.

The last item we will look at in Part I of this tutorial is employing the Structure I showed at the beginning of this tutorial to retrieve some attributes of a file, take those attributes and populate a Generic List(Of FileInformation) back to the calling method. Before I can show that method, however, I need to show the method that is referenced in this function where it checks to see if the file is open before we attempt to retrieve attributes from it. First, the method to check as see if the file is currently open:

#Region " IsFileOpen "
	''' <summary>
	''' Method to determine if a file is open
	''' </summary>
	''' <returns>Boolean value</returns>
	Public Function IsFileOpen() As Boolean
		'always use a try...catch to deal 
		'with any exceptions that may occur
		Try
			'check if the file exists, if it 
			'doesnt exist raise an error
			If Not System.IO.File.Exists(_fileName) Then
				_status = False
				Throw New FileNotFoundException(_fileName + " could not be found!")
			Else
				Dim stream As FileStream = System.IO.File.OpenRead(_fileName)
				stream.Close()
				_status = True
			End If
		Catch
			_status = True
		End Try
		Return _status
	End Function
#End Region



Now for the implemntation of the Structure:

#Region " GetFileInformation"
	''' <summary>
	''' Function to retrieve all the attributes of
	''' the file provided
	''' </summary>
	''' <returns>A Generic list of the attributes</returns>
	''' <remarks></remarks>
	Public Function GetFileInformation() As List(Of FileInformation)
		Dim finfo As FileInformation
		Dim info As New FileInfo(_fileName)
		Dim infoList As New List(Of FileInformation)
		Try
			'First make sure the file actually exists
			If Not File.Exists(_fileName) Then
				'File doesnt exist so set status to false
				'and throw a FileNotFoundException
				_status = False
				Throw New FileNotFoundException(_fileName + " could not be found!")
			Else
				'File exists, now make sure it isnt already open
				If Not IsFileOpen() Then
					'File isnt open so we now set all the attributes of the file
					finfo.FileCreatedOn = info.CreationTime.ToShortDateString
					finfo.FileExtension = info.Extension
					finfo.HiddenStatus = FileAttributes.Hidden
					finfo.LastAccess = info.LastAccessTime.ToShortDateString
					finfo.LastWrite = info.LastWriteTime.ToShortDateString
					finfo.Name = info.Name
					finfo.ReadOnlyStatus = FileAttributes.ReadOnly
					finfo.FileLocation = info.DirectoryName
					finfo.FileSize = info.Length
					infoList.Add(finfo)
				Else
					'Throw an Exception letting the user know the file they're
					'search is currently open and they need to close it first
					Throw New Exception("The file you're searching is currently open. Please close the file and try again.")
				End If
			End If
		Catch ex As FileNotFoundException
			_status = False
			_returnMessage = ex.Message
			Return Nothing
		Catch ex As Exception
			_status = False
			_returnMessage = ex.Message
			Return Nothing
		End Try
		Return infoList
	End Function
#End Region



The debate rages on about the use of Structure (struct in C#) but I am one on the ones for their use. Take this example, I needed an object to hold a small amount of related data, and instead of needing its own class I can encapsulate it into a Structure.

That is Part I of the System.IO in C# Tutorial, at the end of Part II I will be including the project files for this class.. I hope you have found this tutorial helpful and useful. Thanks for reading

:)

This post has been edited by PsychoCoder: 28 December 2007 - 06:29 AM


Is This A Good Question/Topic? 1
  • +

Replies To: Part I - System.IO in VB.Net

#2 RodgerB  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 66
  • View blog
  • Posts: 2,284
  • Joined: 21-September 07

Posted 28 December 2007 - 12:05 AM

Excellent Tutorial PsychoCoder, as always.

I'd just like to comment on the ReadSpecifiedLine function; wouldn't the code below be much simpler and faster than what you have used?

Using lineByLine As New IO.StreamReader(_fileName)
	Dim lineCount As Integer = 0
	While Not lineByLine.EndOfStream
		lineByLine.ReadLine()
		If lineCount = line Then
			lineText = lineByLine.ReadLine()
		End If
		lineCount += 1
	End While
End Using


Using the string functions should be avoided where possible imo, they are slow, tedious and should be used if there is no other options available. You probably already know this though, sorry for being a whore. :)
Was This Post Helpful? 0
  • +
  • -

#3 PsychoCoder  Icon User is offline

  • Google.Sucks.Init(true);
  • member icon

Reputation: 1642
  • View blog
  • Posts: 19,853
  • Joined: 26-July 07

Posted 28 December 2007 - 06:24 AM

Thanks for the idea, I'm making the changes to the tutorial and my Class Library, plus that's a lot easier to read
Was This Post Helpful? 0
  • +
  • -

#4 radumaster  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 2
  • Joined: 07-January 08

Posted 07 January 2008 - 11:01 AM

Hi there.
Great job with the tutorial! Congratulations.
About what RogerB said. Is it necessary to go all the way to the endofstream? We could break out of that while when we found the line that we wanted.
Regards!
Was This Post Helpful? 0
  • +
  • -

#5 RodgerB  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 66
  • View blog
  • Posts: 2,284
  • Joined: 21-September 07

Posted 09 January 2008 - 09:03 PM

View Postradumaster, on 8 Jan, 2008 - 05:01 AM, said:

Hi there.
Great job with the tutorial! Congratulations.
About what RogerB said. Is it necessary to go all the way to the endofstream? We could break out of that while when we found the line that we wanted.
Regards!


Good point, it would be unnecessary to go all the way to EndOfStream when reading a singular line. I must have missed it as I was adapting my code to PsychoCoder's previous code (whether he broke the loop or not I haven't a clue). :)
Was This Post Helpful? 0
  • +
  • -

#6 Rozie0910  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 19
  • Joined: 13-October 08

Posted 15 October 2008 - 09:33 PM

this is my code..
why it cant read from the destination..
i also use texbox to make it copy from the destination to the textbox..
but i cant read at all...
anything wrong with the coding..
could some one help me..


Dim _status As Boolean
Dim _returnMessage As String
Dim line As Integer
Dim contents As String = String.Empty
'always use a try...catch to deal
'with any exceptions that may occur
Try
'create a new TextReader and open our file
Using reader As TextReader = New StreamReader("C:\Documents and Settings\cmg\Desktop\website.txt")
'now read the entire file at once into our variable
contents = reader.ReadToEnd().ToString()
End Using
_status = True
Catch ex As FileNotFoundException
_status = False
contents = String.Empty
_returnMessage = ex.Message
Catch ex As Exception
_status = False
'deal with any errors
_returnMessage = ex.Message
contents = String.Empty
End Try

This post has been edited by Rozie0910: 15 October 2008 - 09:36 PM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1