Niestrukturalna obsługa wyjątków Do ustawienie pułapkowania błędów w VB 6 stosuje się wyrażenie On Error. W VB.Net korzysta się z wyrażenia Try ... Catch (aby wyeliminować wyrażenie GoTo) On Error (Go To) ustawia się przed miejscem, w którym spodziewany jest błąd w jakiejś procedurze. Zanim pojawi się kod z obsługą błędów pojawić się powinno wyrażenie Exit Sub (aby nie wykonywać obsługi błędu, kiedy on nie wystąpił) Obiekt Err istnieje w zasięgu globalnym i zawiera stan błędów, które mogły wystąpić. Własność Number oddaje numer błędu, własność Description jest opisem błędu Private Sub drvList_Change() On Error GoTo driveError dirList.Path = drvList.Drive Exit Sub driveError: MsgBox Err.Description, vbExclamation, "Drive Error" End Sub Wyrażenie Resume Resume pozwala określić, do którego miejsca powinno wrócić sterowanie wykonaniem programu. Miejsce to może być określone etykietą albo wyrażeniem Next. W przypadku Next wykonywanie programu będzie kontynuowane począwszy od wyrażenie następującego po wyrażeniu powodującym błąd Private Sub drvList_Change() On Error GoTo driveError retryDrive: dirList.Path = drvList.Drive Exit Sub driveError: Dim response As Integer, description As Integer description = vbExclamation + vbRetryCancel response = MsgBox(Err.Description, description, "Drive Error") If response = vbRetry Then Resume retryDrive End If End Sub Wyrażenie On Error Resume Next pozwala opuścić wszystkie błędy wykonania, Wyrażenie On Error GoTo 0 wyłącza pułapkowanie Private Sub drvList_Change() On Error Resume Next dirList.Path = drvList.Drive End Sub Zgłaszanie błędu Do zgłoszenia błędu (ponownego jego zgłoszenia) używa się metody Raise obiektu Err. description = "Unable to process the data provided" Err.Raise Err.Number, "myObject", description W przykładzie obsługiwane są wszystkie błędy, które mogą zostać zgłoszone przez InputBox, za wyjątkiem niezgodnego typu danych (Error code 13). Dim age As Integer On Error GoTo incorrectDataType age = InputBox("Enter your name", "Age") Me.Print "You are " & age & " years old" Exit Sub incorrectDataType: If Err.Number = 13 Then Err.Raise 13 Else MsgBox Err.description, vbExclamation, "Error" End If Strukturalna obsługa błędów (wyjątków) Wyrzucanie i przechwytywanie wyjątków (zgłaszanie i obsługiwanie) Wyjątki są obiektami. Służą one do przenoszenia informacji, które generowane są w szczególnych momentach wykonywania programu. Można powiedzieć, że wyjątek to sygnał, który jest emitowany w sytuacji krytycznej. Sygnał ten należy przechwycić, aby na sytuację krytyczną odpowiednio zareagować. Klasą bazową wszystkich wyjątków jest System.Exception. W środowisku .Net zaimplementowano szereg klas wyjątków, m.in.: • ArgumentNullException (używany gdy argumentem metody jest Nothing), • InvalidCastException, (błędne rzutowanie typu) • OverflowException, (wystąpienie przepełnienia). Klasy wyjątków posiadają szereg metod i właściwości. Są to, m.in.: Message (właściwość tylko do odczytu, ustawiana w konstruktorze podczas tworzenia obiektu wyjątku) HelpLink (właściwość do odczytu i zapisu, określająca powiązanie z plikiem pomocy dotyczącego wyjątku) StackTrace (właściwość tylko do odczytu ustawiana przez środowisko uruchomieniowe (runtime), dostarczająca informacje o śladzie stosu dla wyrzucanego błędu (metodach, poprzez które był propagowany wyjątek)). Wyrzucanie i przechwytywanie wyjątków jest mechanizmem, który pozwala reagować na krytyczne sytuacje. Do implementacji tego mechanizmu używa się wyrażenia Throw, obiektu wyjątku oraz bloku Try...Catch. Wyrażenie Throw Throw służy do wyrzucania wyjątków. Aby wyrzucić wyjątek na początek tworzy się obiekt wyjątku, a następnie obiekt ten przekazuje się do wyrażenia Throw. Throw New System.Exception( ) Wyrażenie Throw umieszczane jest w metodach. Wykonanie Throw natychmiast kończy metodę, w której jest umieszczone (podobnie jak Return). Jednak zakończenie działania metody przez wyrzucenie wyjątku jest przypadkiem specjalnym. Wartość zwraca przez metodę przerwaną przez wykonanie Throw nie jest określona. Metody zgłaszające wyjątek mogą być wywoływane wewnątrz innych metod. W takich przypadkach wyrzucanie wyjątków przez metody wewnętrzne przerywa działanie metod zewnętrznych. Jeśli zagnieżdżeń wywołań jest więcej, następuje propagacja wyrzucanego wyjątku (i przerywania metod). Aby zakończyć propagację wyrzucanego wyjątku należy go przechwycić. Jeśli się tego nie zrobi, program zakończy się błędem. Option Strict On Imports System Namespace ExceptionHandling Class Tester Shared Sub Main() Console.WriteLine("Enter Main...") Dim t As New Tester t.Run() Console.WriteLine("Exit Main...") End Sub 'Main Public Sub Run() Console.WriteLine("Enter Run...") Func1() Console.WriteLine("Exit Run...") End Sub 'Run Public Sub Func1() Console.WriteLine("Enter Func1...") Func2() Console.WriteLine("Exit Func1...") End Sub 'Func1 Public Sub Func2() Console.WriteLine("Enter Func2...") Throw New System.Exception Console.WriteLine("Exit Func2...") End Sub 'Func2 End Class 'Tester End Namespace 'ExceptionHandling Wynik działania programu: Enter Main... Enter Run... Enter Func1... Enter Func2... Unhandled Exception: System.Exception: Exception of type System.Exception was thrown. at DebuggingVB.ExceptionHandling.Tester.Func2( ) in C:...\Module1.vb:line 27 at DebuggingVB.ExceptionHandling.Tester.Func1( ) in C:...\Module1.vb:line 21 at DebuggingVB.ExceptionHandling.Tester.Run( ) in C:...\Module1.vb:line 14 at DebuggingVB.ExceptionHandling.Tester.Main( ) in C:...\Module1.vb:line 8 Wyrażenie Try...Catch Wyrażenie Try..Catch służy do przechwytywania wyjątków. W bloku Try umieszcza się kod, w którym mogą pojawić się wyjątki, natomiast obsługę wyjątków umieszcza się w bloku Catch. Składnia tego wyrażenia jest następująca: Try [ tryStatements ] [ Catch [ exception [ As type ] ] [ When expression ] [ catchStatements ] ] [ Exit Try ] ... [ Finally [ finallyStatements ] ] End Try Wiele elementów w powyższym wyrażeniu jest opcjonalnych. Użycie bloku Try...Catch w postaci generycznej (najprostszej) przedstawia następujący przykład: Option Strict On Imports System Namespace ExceptionHandling Class Tester Shared Sub Main() Console.WriteLine("Enter Main...") Dim t As New Tester t.Run() Console.WriteLine("Exit Main...") End Sub 'Main Public Sub Run() Console.WriteLine("Enter Run...") Func1() Console.WriteLine("Exit Run...") End Sub 'Run Public Sub Func1() Console.WriteLine("Enter Func1...") Func2() Console.WriteLine("Exit Func1...") End Sub 'Func1 Public Sub Func2() Console.WriteLine("Enter Func2...") Try Console.WriteLine("Entering Try block...") Throw New System.Exception Console.WriteLine("Exitintg Try block...") Catch Console.WriteLine("Exception caught and handled") End Try Console.WriteLine("Exit func2...") End Sub 'Func2 End Class 'Tester End Namespace 'ExceptionHandling Wynik działania programu (wyjątek wygenerowany w Func2 obsłużony w Func2): Enter Main... Enter Run... Enter Func1... Enter Func2... Entering try block... Exception caught and handled! Exit Func2... Exit Func1... Exit Run... Exit Main... Inny przykład (wyjątek wygenerowany w Func2 obsłużony w Func1): Option Strict On Imports System Namespace ExceptionHandling Class Tester Shared Sub Main() Console.WriteLine("Enter Main...") Dim t As New Tester t.Run() Console.WriteLine("Exit Main...") End Sub 'Main Public Sub Run() Console.WriteLine("Enter Run...") Func1() Console.WriteLine("Exit Run...") End Sub 'Run Public Sub Func1() Console.WriteLine("Enter func1...") Try Console.WriteLine("Entering Try block...") Func2() Console.WriteLine("Exiting Try block...") Catch Console.WriteLine("Exception caught and handled") End Try Console.WriteLine("Exit func1...") End Sub 'Func1 Public Sub Func2() Console.WriteLine("Enter Func2...") Throw New System.Exception Console.WriteLine("Exit Func2...") End Sub 'Func2 End Class 'Tester End Namespace 'ExceptionHandling Wynik działania programu: Enter Main... Enter Run... Enter Func1... Entering try block... Enter Func2... Exception caught and handled! Exit Func1... Exit Run... Exit Main... Poza tym, że można w ogóle przechwytywać wyjątki, można jeszcze zdefiniować typ wyjątków jakie mają zostać przechwycone. Przykład przechwytywania wyjątków konkretnych typów przedstawiony jest poniżej: Option Strict On Imports System Namespace ExceptionHandling Class Tester Public Sub Run() Try Dim a As Double = 5 Dim b As Double = 0 Console.WriteLine("Dividing {0} by {1}...", a, b) Console.WriteLine("{0} / {1} = {2}", _ a, b, DoDivide(a, b)) ' most derived exception type first Catch e As System.DivideByZeroException Console.WriteLine("DivideByZeroException caught!") Catch e As System.ArithmeticException Console.WriteLine("ArithmeticException caught!") ' generic exception type last Catch Console.WriteLine("Unknown exception caught") End Try End Sub ' do the division if legal Public Function DoDivide(ByVal a As Double, ByVal b As Double) As Double If b = 0 Then Throw New System.DivideByZeroException End If If a = 0 Then Throw New System.ArithmeticException End If Return a / b End Function Public Shared Sub Main() Console.WriteLine("Enter Main...") Dim t As Tester = New Tester t.Run() Console.WriteLine("Exit Main...") End Sub End Class End Namespace Wynik działania programu: Enter Main... Dividing 5 by 0... DivideByZeroException caught! Exit Main... Uwaga: Kolejność umieszczania bloków Catch z konkretnymi typami wyjątków ma znaczenie. Jeśli bowiem pierwszy z bloków Catch będzie przechwytywał wyjątki klasy nadrzędnej (rodzicielskiej), zaś pozostałe bloki Catch – wyjątki klas potomnych, to faktycznie nigdy sterowanie nie dojdzie do bloków Catch z wyjątkami klas potomnych. Powodem jest to, że pierwszy blok Catch dokona obsługi takich wyjątków (wszędzie tam, gdzie jest referencja do obiektu klasy rodzicielskiej można wstawić referencję do obiektu klasy potomnej). W przykładzie powyżej wyjątek DivideByZeroException jest klasą potomną klasy ArithmeticException. Stąd, jeśli pierwszy blok Catch obsługiwałby wyjątek klasy ArithmeticException, to sterowanie programem nigdy nie doszłoby do bloku Catch z wyjątkiem typu DivideByZeroException. Blok Finally jest blokiem, który jeśli został zadeklarowany, to wykona się zawsze (niezależnie od tego, czy został wyrzucony wyjątek, czy też nie). W bloku Finally nie można używać Exit, Throw, Return ani GoTo (tzn. nie można go przerywać wymienionymi instrukcjami). Option Strict On Imports System Namespace ExceptionHandling Class Tester Public Sub Run() Try Console.WriteLine("Open file here") Dim a As Double = 5 Dim b As Double = 0 Console.WriteLine("{0} / {1} = {2}", a, b, DoDivide(a, b)) Console.WriteLine("This line may or may not print") ' most derived exception type first Catch e As System.DivideByZeroException Console.WriteLine( _ "DivideByZeroException! Msg: {0}", e.Message) Console.WriteLine( _ "Helplink: {0}", e.HelpLink) Console.WriteLine( _ "Stack trace: {0}", e.StackTrace) Catch Console.WriteLine("Unknown exception caught!") Finally Console.WriteLine("Close file here.") End Try End Sub 'Run ' do the division if legal Public Function DoDivide( _ ByVal a As Double, ByVal b As Double) As Double If b = 0 Then Dim e As New System.DivideByZeroException e.HelpLink = "http://www.LibertyAssociates.com" Throw e End If If a = 0 Then Throw New System.ArithmeticException End If Return a / b End Function 'DoDivide Shared Sub Main() Console.WriteLine("Enter Main...") Dim t As New Tester t.Run() Console.WriteLine("Exit Main...") End Sub 'Main End Class 'Tester End Namespace 'ExceptionHandling Wynik działania programu Output: Enter Main... Open file here DivideByZeroException! Msg: Attempted to divide by zero. HelpLink: http://www.libertyassociates.com Stack trace: at ExceptionHandling.Tester.DoDivide(Double a, Double b) in ...Module1.vb:line 38 at ExceptionHandling.Tester.Run( ) in ...Module1.vb:line 10 Close file here. Exit Main... Wyjątki użytkownika Aby zaimplementować własny wyjątek (dostarczając mu arbitralnych właściwości i metod) należy utworzyć klasę wyjątku dziedziczącą po klasie System.ApplicationException. Przykład: Option Strict On Imports System Namespace ExceptionHandling ' custom exception class Public Class MyCustomException Inherits System.ApplicationException Public Sub New(ByVal message As String) ' pass the message up to the base class MyBase.New(message) End Sub 'New End Class 'MyCustomException Class Tester Public Sub Run() Try Console.WriteLine("Open file here") Dim a As Double = 0 Dim b As Double = 5 Console.WriteLine("{0} / {1} = {2}", a, b, DoDivide(a, b)) Console.WriteLine("This line may or may not print") ' most derived exception type first Catch e As System.DivideByZeroException Console.WriteLine( _ "DivideByZeroException! Msg: {0}", e.Message) Console.WriteLine("HelpLink: {0}", e.HelpLink) ' catch custom exception Catch e As MyCustomException Console.WriteLine( _ "MyCustomException! Msg: {0}", e.Message) Console.WriteLine("HelpLink: {0}", e.HelpLink) Catch ' catch any uncaught exceptions Console.WriteLine("Unknown exception caught") Finally Console.WriteLine("Close file here.") End Try End Sub 'Run ' do the division if legal Public Function DoDivide( _ ByVal a As Double, ByVal b As Double) As Double If b = 0 Then Dim e As New DivideByZeroException e.HelpLink = "http://www.libertyassociates.com" Throw e End If If a = 0 Then ' create a custom exception instance Dim e As New _ MyCustomException("Can't have zero divisor") e.HelpLink = _ "http://www.libertyassociates.com/NoZeroDivisor.htm" Throw e End If Return a / b End Function 'DoDivide Shared Sub Main() Console.WriteLine("Enter Main...") Dim t As New Tester t.Run() Console.WriteLine("Exit Main...") End Sub 'Main End Class 'Tester End Namespace 'ExceptionHandling Wynik działania programu: Enter Main... Open file here MyCustomException! Msg: Can't have zero divisor HelpLink: http://www.libertyassociates.com/NoZeroDivisor.htm Close file here. Exit Main... Uwaga: Konstruktory nie mogą być dziedziczone, dlatego każda klasa potomna powinna mieć zaimplementowany własny konstruktor. ************ Visual Basic .NET expands file-handling capabilities while providing compatibility with previous versions of Visual Basic file I/O functions. Visual Basic 6.0 In Visual Basic 6.0, file handling is accomplished using various file I/O functions such as Open, Input, Output, and Append. The File System Object provides an object-oriented method of working with files. Visual Basic .NET In Visual Basic .NET, file handling is accomplished through the System.IO namespace, which duplicates and expands upon the File System Object. In addition, the System.IO.File namespace includes functions that provide compatibility with the older Visual Basic file I/O functions. The FileStream class provides access to standard input and output files and error devices. The following table lists file-related enumerations available in Visual Basic .NET. Enumeration FileAccess Enumeration FileMode Enumeration FileShare Enumeration FileAttributes Enumeration Purpose Defines constants for read, write, or read/write access to a file Specifies how the operating system opens a file Provides constants for controlling the level of access other FileStream members have to the same file Provides access to stored attributes, such as whether a file is a directory, is encrypted, hidden, or read-only, or is a system file or a temporary file Visual Basic allows you to process drives, folders, and files in several different ways: through the use of the .NET System.IO model, through traditional methods such as the FileOpen and Write functions, and through the File System Object (FSO) model. The following sections discuss these methods in detail. The .NET System.IO model provides an object-based tool for working with folders and files. Like FileSystemObject (as described in Accessing Files with FileSystemObject ), it allows you to use standard object.method syntax — with its own set of properties, methods, and events — to process text and data, giving your applications the ability to read from and write to files easily. The .NET System.IO namespace includes a class library that facilitates string, character, and file manipulation. These classes contain properties, methods, and events for creating, copying, moving, and deleting files. And, since both strings and numeric data types are supported, they also allow you to incorporate data types in files. The most commonly used classes are FileStream, BinaryReader, BinaryWriter, StreamReader, and StreamWriter. File Operations Do operacji na plikach na platformie .NET wprowadzono przestrzeń nazw System.IO. W przestrzeni tej zawarte są klasy, które pozwalają czytać dane z i pisać dane do plików fizycznych bądź też strumieni. Są tam też klasy pozwalające wykonywać operacje na systemie plików (jak np. wylistowywanie katalogów, monitorowanie zmian w systemie plików, itp.). W VB.Net wprowadzono możliwość asynchronicznego czytania i pisania plików. Directory Listing We wcześniejszych wersjach VB do wylistowania katalogów służyła funkcja Dir(). Sposób jej wykorzystania przedstawia poniższy przykład: Dim sFile As String 'Obtain an initial value for sFile sFile = Dir("C:") 'Loop until Dir() returns empty string Do Until sFile = vbNullString Debug.Print sFile sFile = Dir() Loop VB 6.0 pozwalał używać Microsoft Scripting Runtime Library. W bibliotece tej udostępniono obiekt Scripting.FileSystemObject oraz obiekty pochodne. W VB 6.0 realizacja zadania wylistowania katalogów wyglądała następująco: '*************************************************** 'This example requires a reference to be set to the 'Microsoft Scripting Runtime '*************************************************** Dim oFS As Scripting.FileSystemObject Dim oFolder As Scripting.Folder Dim oFile As Scripting.File 'Create the FileSystemObject Object Set oFS = New Scripting.FileSystemObject 'Get reference to folder through FileSystemObject Set oFolder = oFS.GetFolder("C:\") 'Enumerate Files For Each oFile In oFolder.Files Debug.Print oFile.Name Next oFile W VB.NET udostępniono przestrzeń System.IO. W przestrzeni tej występuje klasa System.IO.Directory, która odpowiedzialna jest za działania na katalogach, oraz klasa System.IO.File , która służy do wykonywania operacji na plikach. Oto przykład, jak można wylistować katalog w VB.NET: Imports SYSTEM.IO Module Module1 Sub Main() 'Obtain reference to Directory Dim oDir As Directory = New Directory("C:\") Dim oFile As File For Each oFile In oDir.GetFiles() debug.WriteLine(oFile.Name) Next End Sub End Module Pliki danych It is important to consider the type and use of data before storing data in local files on a client.When accessing data files, you will most likely use ADO and databases.The benefits of using databases as opposed to binary files are tremendous, with indexing and sorting and the like built-in. For small amounts of data, such as configuration data, you may want to store information in the registry. From the standpoint of debugging, you may want to store the information locally in a text file—this will allow you to view the information with a simple text editor such as Notepad.This can aid in the debugging process.That being said, you may find that sometimes you need to store information in data files on the client. Data files on the client are usually in binary format. As mentioned earlier in the chapter, the System.IO namespace is used to provide us with file access methods. At the top of our module, we need to provide an Imports statement for System.IO namespace.The following example shows us how to use the System.IO namespace to perform file I/O to and from a data file. The BinaryReader and BinaryWriter classes may be more familiar to Visual Basic users as DataReader and DataWriter from the filesystem object. Although the names have been changed for the System.IO model, the functionality remains similar. BinaryReader is used for reading strings and primitive data types, whereas BinaryWriter writes strings and primitives types from a stream.The following example demonstrates reading from a binary file and writing to a binary file: 1 Dim InFile As String 2 Dim OutFile As String 3 InFile = "c:\SomeInFile.bin" 4 OutFile = "c:\someOutFile.Bin" 5 Dim inf As New System.IO.File(InFile) 6 Dim outf As New System.IO.File(OutFile) 7 Dim x As Integer 8 Dim aRetVal As Integer ' create streams for input and output 9 Dim myInstream As System.IO.FileStream 10 Dim myOutstream As system.IO.FileStream 11 Dim aFoo(100) As System.Byte ' data to read and write 12 For x = 1 To 99 aFoo(x) = x 13 Next 14 Try 15 myInstream = inf.OpenRead ' Open a new stream for input. 16 myOutStream = outf.OpenWrite 17 aRetVal = myoutstream.write(aFoo, 0, 10) 18 myoutstream.Flush() 19 aRetVal = myInstream.Read(aFoo, 0, 10) ' read 10 bytes 20 Catch IOExcep As IO.IOException 21 ' Some kind of error occurred. Display error message 22 MessageBox.Show(IOExcep.Message) 23 Finally 24 myInStream.Close() ' Close the files 25 myOutStream.Close() 26 End Try In this code fragment, the file name variables are declared and assigned in lines 1 through 4.As we progress to lines 5 and 6, the objects for the files are declared and instantiated. Line 7 declares an integer that will be used later in the load logic.The stream objects for input and output are created and instantiated. Line 8 declares an integer to hold the returned value from the call. Lines 9 and 10 initialize the stream variables. In lines 11 through 13, the variable used to send and receive data is initialized and loaded.We load the variable with numeric data. Lines 15 and 16 open the streams for reading and writing and associate them with the files. Line 17 writes some data to the file and line 18 completes the operation by flushing the buffer.The data written to the file will look like this: 1234567891 Line 19 reads data from the other file (we assume that the file exists; if it doesn’t exist, we would get an error). Assuming we were to use the file we had written previously, the data read from the file will look like this: 1234567891 Lines 20 through 26 contain exception-handling code, which will handle any exceptions that occur. Lines 24 and 25 the close the streams. Line 26 is the end of the exception-handling code. That’s all there is to reading and writing to files. Additionally, the filesystem object provides other methods for file I/O, as do many third-party products.The filesystem object has been available for use within Visual Basic since Visual Basic 6.0.This is an object that provides methods for manipulating a computer’s files. The following code fragment demonstrates the use of the filesystem object: 1 Set fs = CreateObject("Scripting.FileSystemObject") 2 Set oFile = fs.CreateTextFile("c:\MyTestFile.txt", True) 3 oFile.WriteLine("This is a test.") 4 oFile.Close Pliki tekstowe The following example shows how to read and write from a text file.This example opens a file, reads one line at a time from the file, converts the line to uppercase, and then appends the line to the output file.Writing to and reading from text files is a common programming task in Visual Basic. Text files are generally carriage-return delimited and are limited to ASCIIreadable characters. Data files generally contain control characters: 1 Imports System.ComponentModel 2 Imports System.Drawing 3 Imports System.WinForms 4 Imports SYSTEM.IO 5 Public Class Case_Converter 6 Private LinesCounted As Integer = 0 7 Public Event Status(ByVal LinesCounted As Integer) 8 Public Event FinishedConverting() 9 Sub ToUpper(ByVal InFile As String, ByVal OutFile As String) ' first handle files 10 Dim inf As New SYSTEM.IO.File(InFile) 11 Dim outf As New SYSTEM.IO.File(OutFile) ' create streams for input and output 12 Dim myInstream As SYSTEM.IO.StreamReader 13 Dim myOutstream As SYSTEM.IO.StreamWriter ' temporary string to hold work 14 Dim mystr As String = " " ' initialize to not empty 15 Dim OutStr As String = " " 16 Try 17 myInstream = inf.OpenText ' Open a new stream for input. ' Do until the stream returns Nothing at end of file. 18 myOutStream = outf.CreateText 19 Do Until isnothing(mystr) 20 mystr = myInstream.ReadLine ' perform conversion 21 OutStr = ucase(mystr) 22 myoutstream.WriteLine(OutStr) 23 LinesCounted += 1 ' Increment line count ' raise an event so the form can monitor progress 24 RaiseEvent Status(LinesCounted) 25 Loop 26 Catch eof As IO.EndOfStreamException ' No action is necessary, the end of the stream has been reached. 27 Catch IOExcep As IO.IOException ' Some kind of error occurred. 28 MessageBox.Show(IOExcep.Message) 29 Finally 30 myInStream.Close() ' Close the files 31 myOutStream.Close() 32 End Try 33 RaiseEvent FinishedConverting() 34 End Sub 35 End Class In this example, we can see that the class Case_Converter contains a method called ToUpper, which includes two parameters: InFile and OutFile. Note that importing the System.IO namespace (shown in line 4 of the code) is very important. This allows us to use the methods and functions contained in that namespace. Next, as we progress through the code, line 6 declares a local variable for use within the class. Lines 7 and 8 declare public events that are exploited later in this chapter. It is good programming practice to declare everything in Visual Basic. NET for type safety as well as to help understand the data in a particular variable. Line 9 is the beginning of the method.When we declare the method, notice that the parameters (InFile and Outfile) include both a type (String) and a calling method (ByVal).This is very important in Visual Studio .NET because the default calling type has changed from Byref to Byval, and you may not get the expected results using the default calling type. NOTE Remember to include the Imports System.IO command at the beginning of your code when you are working with file I/O. If you don’t include it, your code won’t compile. This is not so much a problem if you are writing a routine from scratch, because Microsoft’s IntelliSense won’t work, and you will quickly be aware of the issue. However, look out for if you are pasting code in from another project. Lines 10 through 15 declare the objects we use to work with file I/O. Some important things to note here are the System.IO.File object, the System.IO.StreamReader object, and the System.IO.StreamWriter object.The System.IO.File class is used to help create FileStream objects and provides routines for creating, copying, deleting, moving, and opening of files. In lines 10 and 11, file objects are created for the input and output files.These are used later with the FileStream objects that are created in lines 12 and 13.The System.IO .StreamReader class implements a text reader that will read characters in from the file.This class does the work when it comes to reading data in from the file.The System.IO.StreamWriter class implements a text writer that will read characters in from the file. Dopisywanie do plików Appending to files is pretty simple. If we use the code shown in the text files example, only a minor change is necessary. Appending means that we have an existing file, and we want to add data to the end of it, which is a common programming task. Oftentimes, you’ll need to write information out to files for logging, troubleshooting, and saving information. 17 myInstream = inf.OpenText ' Open a new stream for input. ' Do until the stream returns Nothing at end of file. 18 myOutStream = outf.CreateText Line 18 would change to: 17 myInstream = inf.OpenText ' Open a new stream for input. ' Do until the stream returns Nothing at end of file. 18 myOutStream = outf.AppendText Changing the stream type from CreateText to AppendText causes text to be appended to the file as opposed to overwriting the file.