Welcome to Dream.In.Code
Getting Help is Easy!

Join 99,783 Programmers for FREE! Ask your question and get quick answers from experts. There are 1,528 online right now! We've got more than 500 tutorials and 2,000 snippets. Join and find out why Dream.In.Code is the #1 programming help community on the internet! Registration is fast and FREE... Join Now!



Part I - System.IO in VB.Net

 
Reply to this topicStart new topic

> Part I - System.IO in VB.Net

PsychoCoder
Group Icon



post 27 Dec, 2007 - 09:40 PM
Post #1


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..
  1. TextReader
  2. TextWriter
  3. StreamReader
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:

CODE

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):

CODE

#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:

CODE

#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:

CODE

#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:

CODE

#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:

CODE

#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:

CODE

#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:

CODE

#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.

CODE

#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:

CODE

#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:

CODE

#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

smile.gif

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


Register to Make This Ad Go Away!

RodgerB
Group Icon



post 28 Dec, 2007 - 12:05 AM
Post #2
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?

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


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. smile.gif

PsychoCoder
Group Icon



post 28 Dec, 2007 - 06:24 AM
Post #3
Thanks for the idea, I'm making the changes to the tutorial and my Class Library, plus that's a lot easier to read

radumaster
*



post 7 Jan, 2008 - 11:01 AM
Post #4
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!

RodgerB
Group Icon



post 9 Jan, 2008 - 09:03 PM
Post #5
QUOTE(radumaster @ 8 Jan, 2008 - 05: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!


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). smile.gif


Fast ReplyReply to this topicStart new topic
3 User(s) are reading this topic (3 Guests and 0 Anonymous Users)
0 Members:

 

Lo-Fi Version Time is now: 7/25/08 01:13AM

Live Help!

Tutorials

Programming

Web Development

Reference Sheets

Code Snippets

Bye Bye Ads

Free DIC T-Shirt

T-Shirt Example

Related Sites

Monthly Drawing

Thumb Drive

Partners

Top Contributors

Top 10 Kudos This Month
-->