It seems that there are a million ways to open and edit a file using Visual Basic, and you are unsure of the differences.
How you edit a file depends on how you first open it. Visual Basic 2005 has some traditional file-editing features that are variations of what it had back in Version 1.0 of the language, and you can use some of the file-editing features provided with the .NET Framework (such as streams). Also, many objects provide options to immediately "serialize" their content to a file in an XML or similar format. This recipe documents some of the common file-editing choices available to you in Visual Basic. It does not provide full source code using each possible option. Instead, it provides an overview of the options available to you.
Visual Basic supports two primary methods of file access:handle-based and streambased.
Handle-based file access
Visual Basic traditionally supports a handle-based method of file management. Each file opened for input or output has a generated numeric ID that is always used to reference that file. The Visual Basic FreeFile() method generates this numeric handle, and the handle is assigned before a file is ever accessed. To open an existing file, you first obtain an ID and then open the file:
Dim fileHandle As Integer = FreeFile( ) FileOpen(fileHandle, "C:\DataFile.dat", OpenMode.Input, _ OpenAccess.Read, OpenShare.Shared)
There are several other functions in Visual Basic that deal with file manipulation, and all of them use the file handle returned from FreeFile(). You must continue to use the handle for all interactions with the opened file until you specifically close the file.
Care must be taken when using FreeFile(). Until you actually use a file handle to open a file, it is considered unused, and FreeFile() will keep returning it again and again because it knows it to be unused. Consider the following code:
Dim fileHandleIn As Integer = FreeFile( ) Dim fileHandleOut As Integer = FreeFile( ) FileOpen(fileHandleIn, inputFilePath, OpenMode.Input) FileOpen(fileHandleOut, outputFilePath, OpenMode.Output)
The problem with this code is that fileHandleIn and fileHandleOut probably contain the same numeric handle. That handle number will get used by the first FileOpen( ) call, leaving the second one to fail. The following code should be used instead:
Dim fileHandleIn As Integer = FreeFile( ) FileOpen(fileHandleIn, inputFilePath, OpenMode.Input) Dim fileHandleOut As Integer = FreeFile( ) FileOpen(fileHandleOut, outputFilePath, OpenMode.Output)
Handle-based files are opened in one of three modes:
There are a few functions that work with all file modes. The FileClose() and Reset() methods let you close a single file and all open files, respectively. The EOF() function indicates whether you have reached the end of a file that you are scanning, although it isn't always reliable with random files. Finally, the Seek() function and Seek() method (two features with the same name) let you determine and move the current position marker within an open file.
Stream-based file access
While Visual Basic continues to support handle-based file access for reasons of compatibility, streams are the preferred file access method in .NET. Streams are defined through the System.IO.Stream class and through several derived classes that enhance that base class (such as providing a stream focused on network data).
Streams provide three basic operations: Read() (and its variations), Write() (with variations), and Seek(). Not all streams support these basic features. You can use the CanRead(), CanWrite(), and CanSeek() methods to determine their availability.
Streams are useful because they let you manage a file at a granular level, through the individual bytes. However, it isn't always convenient to constantly convert non-Byte data back and forth to Bytes. To make file reads and writes easier, the System.IO namespace also includes stream readers and stream writers as separate classes. These distinct classes get wrapped around a stream and provide start-to-finish reading or writing of a stream's content. The StreamReader class wraps a Stream object, providing simplified reading of the stream's content. For instance, the ReadLine() method returns the next line in the stream as a string:
Dim oneLine As String Dim scanFile As New IO.StreamReader("c:\data.txt") Do While Not scanFile.EndOfStream oneLine = scanFile.ReadLine( ) ' ----- Process the line contents here. Loop scanFile.Close( )
The StreamWriter class provides the opposite features, allowing you to write strings and other basic data types to a stream.
Related stream readers and writers include the StringReader and StringWriter pair (identical to the StreamReader and StreamWriter classes, but using a String as the underlying storage content instead of a Stream) and the BinaryReader and BinaryWriter classes, which provide a simplified method of reading and writing binary and core data-type content.
Some of the objects and features in the My.Computer. FileSystem object provide access to file streams. My.Computer. FileSystem.OpenTextFileReader() opens a StreamReader based on an existing file path. You can also create a new file stream using the System.IO.File.Create() method or other similar methods.
The My namespace includes a TextFieldParser object that provides simplified access to files with columnar data in either delimited columns (such as tab-delimited fields) or fixed-width fields.
For those objects that support serialization of their content to XML files, the basic transport between the object and the destination file is the Stream. Streams also appear when data needs to pass through some sort of conversion on its way to another destination. The cryptography features in the System.Security.Cryptography namespace frequently use streams during encryption and hashing operations.
Other recipes in this chapter provide specific examples using the file-processing features available to Visual Basic. Most of the recipes focus on stream-based file access because that is the preferred file-interaction method in .NET.