Chapter 9. Controlling Code Flow

Directives

12.1 Save all temporary files in the user's Temp folder.

At times, it becomes necessary to create temporary files for all sorts of reasons. If a file is truly temporary (that is, it doesn't need to be persisted for a future session), save the file in the user's designated temporary folder.

In the past, it was often enough to assume that the user's temporary folder was \Windows\Temp. This is no longer the case especially with many users sharing computers under different profiles. You can determine a user's temporary folder in a number of ways, including polling an environment variable and calling the API. However, the easiest (and best) way is to use a simple method in the .NET Framework. You might think that the method would be part of System.Environment (at least that's where I originally looked for it). However, the method is in fact available via the Path class.

Note

Directory names are returned as short file names by GetTempPath, as shown in Figure 12-3.


 

Figure 12-3. GetTempPath returns short file names.

graphics/f12ln03.jpg

Incorrect:
' Create a temporary backup of the file we're about to manipulate. ' The temp path is determined by checking the TEMP environment ' variable. Dim strTempPath = _       System.Environment.ExpandEnvironmentVariables("%TEMP%") Dim strTempFile = strTempPath & "\" & _                   System.IO.Path.GetFileName(strSourceFile) System.IO.File.Copy(strSourceFile, strTempFile) ' Do something with the file here...  ' Delete the temporary file. System.IO.File.Delete(strTempFile) 
Correct:
' Create a temporary backup of the file we're about to manipulate. Dim strTempFile = System.IO.Path.GetTempPath & _                   System.IO.Path.GetFileName(strSourceFile) System.IO.File.Copy(strSourceFile, strTempFile) ' Do something with the file here...  ' Delete the temporary file. System.IO.File.Delete(strTempFile) 

12.2 Save temporary files with a system-assigned temporary file name.

In addition to saving temporary files in the user's temporary folder, you should save the files with a system-assigned temporary filename. Doing so ensures that you won't have an issue with duplicate temporary file names. To retrieve a system-assigned temporary filename, call System.IO.Path.GetTempFileName. There's really only one important caveat to this property call: it automatically creates a zero-byte file with the name it passes back to you. This ensures that nothing else can use this file name, but it also means that you must delete the file if you plan on saving a file using the name. Consider this code:

' Create a temporary backup of the file we're about to manipulate. Dim strTempFile = System.IO.Path.GetTempFileName System.IO.File.Copy(strSourceFile, strTempFile) 

This code is similar to the previous example, but it contains a nasty bug. Executing this code causes the exception shown in Figure 12-4. The exception occurs because File.Copy throws an exception if the destination file exists, which it does because GetTempFileName created it.

Figure 12-4. You have to account for the fact that GetTempFileName automatically creates a zero-byte file.

graphics/f12ln04.jpg

Tip

When you are finished with the temporary file, delete it. Windows will not delete your temporary files you.


 

Incorrect:
' Create a temporary backup of the file we're about to manipulate. System.IO.File.Copy(strSourceFile, "temp.txt") ' Do something with the file here...  ' Delete the temporary file. System.IO.File.Delete("temp.txt") 
Correct:
' Create a temporary backup of the file we're about to manipulate. Dim strTempFile = System.IO.Path.GetTempFileName ' Delete the zero-byte file created by GetTempFileName System.IO.File.Delete(strTempFile) ' Copy the file. System.IO.File.Copy(strSourceFile, strTempFile) ' Do something with the file here...  ' Delete the temporary file. System.IO.File.Delete(strTempFile) 

12.3 Close all files that you open as soon as you no longer need access to them.

A good rule of thumb is that you should close everything that you open, and this rule is quite applicable to files. Not only should you close all files that you open, you should attempt to do so as quickly as possible so that the file is available for other operations. Remember, the garbage collector frees up resources as it sees fit, so if you rely on an object variable going out of scope to close a file, it might be quite some time before the file is actually closed. Notice in the incorrect code shown next that objStream.Close isn't explicitly called. This means the text file isn't actually closed, and it won't be closed until the garbage collector gets around to collecting the object. In the correct example, Close is called, and the file is therefore made immediately available to any application that wishes to access it.

Incorrect:
' Open a new stream writer to the log file. Dim objStream As New System.IO.StreamWriter(g_strErrorLogFileName, _                                             True) Dim strLogText As String  ' Create the log text. strLogText = DateTime.Now & ControlChars.CrLf & _              "Exception: " & e.Message & ControlChars.CrLf & _              "Module: " & strModule & ControlChars.CrLf & _              "Method: " & e.TargetSite.Name & ControlChars.CrLf & _              "Stack: " & e.StackTrace & ControlChars.CrLf ' Write the exception message. objStream.WriteLine(strLogText) ' Flush the text to the log file. objStream.Flush() ' Note that the file is not explicitly closed... 
Correct:
' Open a new stream writer to the log file. Dim objStream As New System.IO.StreamWriter(g_strErrorLogFileName, _                                             True) Dim strLogText As String  ' Create the log text. strLogText = DateTime.Now & ControlChars.CrLf & _              "Exception: " & e.Message & ControlChars.CrLf & _              "Module: " & strModule & ControlChars.CrLf & _              "Method: " & e.TargetSite.Name & ControlChars.CrLf & _              "Stack: " & e.StackTrace & ControlChars.CrLf ' Write the exception message. objStream.WriteLine(strLogText) ' Flush the text to the log file. objStream.Flush() ' Close the log file. objStream.Close() 

12.4 Never hard-code a path in an application.

In general, hard-coding assumptions into any program is a bad idea. When the assumption is a path, it's a really bad idea. It's a frustrating experience to build and test a fantastic application, only to have it fail on startup the first time it's deployed to a user's computer because the paths on the user's computer differ from the paths on your computer. There are a number of ways to work around this issue, including:

  • Use a relative path

  • Prompt the user for a required path

  • Search for files on the hard drive to determine a path

The approach that you choose will depend entirely on the situation. Most often, using relative paths is a great approach. For example, if your application will make use of AVI files, you can have your installation program install the animations in a folder titled \AVI under your main application folder. Then, your program could get the path to the files using code such as this:

Dim strAVIPath As String strAVIPath = System.Environment.CurrentDirectory & _              System.IO.Path.DirectorySeparatorChar & "AVI" 

12.5 Use System.IO.Path to manipulate file paths.

At the beginning of this chapter, I discussed how System.IO.Path can be used to manipulate path strings. Whenever possible, you should use the members of System.IO.Path in place of any other approaches (such as custom code routines). Using System.IO.Path gives your application some level of platform independence and helps ensure that your code will still continue to execute as changes are made to the environment.

Practical Application
12.5.1 Use the system-defined directory separator when building paths.

It's really tempting to assume that the backslash character (\) is the directory separator on a user's computer. For example, you've probably written code similar to this:

Dim strFile As String = strSourcePath & "\" & strName 

One of the exciting things about .NET and the common language runtime in particular is the potential for developing cross-platform applications (can you imagine a CLR for the Apple Macintosh or for Linux?). If this ever happens, we'll all have to rethink many of our assumptions. By hard-coding assumptions such as the backslash character in this statement, you run the risk of the code failing in an environment where the assumption is no longer valid. A better way to rewrite the preceding statement is like this:

Dim strFile As String = strSourcePath & _                        System.IO.Path.DirectorySeparatorChar & strName 

Caution

Don't confuse PathSeparator with DirectorySeparatorChar. PathSeparator returns the character used to delineate multiple paths in a string (a semicolon on most Windows-based computers).


 

Note

This practical application has no correct/incorrect example.


 

12.6 Default saving files in the user's My Documents folder.

When Windows 95 first introduced the concept of a My Documents folder, many users (including myself) were reluctant to accept the idea. This was due to the fact that users had no formal place to store their documents in the past, and therefore they created their own storage structures. Files were often saved in the folder or a subfolder of the application that used them. Since then, users (and developers) have finally come around to supporting the My Documents concept. Visual Studio .NET defaults saving new projects under \My Documents, for example.

When you prompt a user to save a new file (as well as when asking the user for a file to open), you should default the path to the user's \My Documents folder. To obtain the \My Documents folder for a user, use the following statement:

 StrMyDocPath = _    System.Environment.GetFolderPath(Environment.SpecialFolder.Personal) 

For example, when showing the Save File Dialog control to allow the user to specify the location and name for a file to be saved, set the default path like this:

SaveFileDialog1.InitialDirectory = _    System.Environment.GetFolderPath(Environment.SpecialFolder.Personal) 

12.7 Add files to a user's Recent Documents list

One nice little feature that isn't taken advantage of often enough is the Recent Documents list available on a user's Start Menu. (See Figure 12-5.) If your application works with documents (files) of any sort, you should consider adding documents to this list as the user opens them.

Figure 12-5. You can (and should) add documents to a user's Recent Documents list.

graphics/f12ln05.jpg

Unfortunately, there is no ".NET" way to add items to a user's Recent Document list. However, it's still possible to accomplish this using a good old-fashioned API call. (OK, they're not old-fashioned yet.) To accomplish this, you first have to add the Declare statement for the API to your class. Here's the declaration. Notice that I've already modified the types to be compatible in .NET, so this statement should be used as-is:

' SHAddRecentDocs is an API function used to add files to a  ' user's Recent Documents folder. Public Const SHARD_PIDL = &H1& Public Const SHARD_PATH = &H2& Private Declare Function SHAddToRecentDocs Lib "shell32" _                             (ByVal dwFlags As Integer, _                              ByVal dwData As StringAs Integer 

Once you've added the API function declaration, you can add files to the user's Recent Documents list using code like this:

Dim intFlag As Integer Dim strFileName As String intFlag = SHARD_PATH ' When adding a file to the user's recent documents list, ' you must supply the full path. strFileName = ("C:\temp.txt") ' Add the file to the list.    Call SHAddToRecentDocs(intFlag, strFileName) 

12.8 Ask for confirmation before deleting an important file.

Deleting a file is dangerous because there is no way to get it back. Remember, the Delete functions of System.IO permanently delete files and directories; they do not send them to the Recycle Bin. When you ask the user for confirmation, display the full path and filename. Consider Figure 12-6 and Figure 12-7. Which would you feel most comfortable answering Yes to? Essentially, you want to put the onus on the user; if the wrong file is deleted, you want to be sure that you gave the user information that was as accurate as possible.

Figure 12-6. How comfortable would you be answering Yes to this question?

graphics/f12ln06.jpg

Figure 12-7. Show the full path when asking for confirmation to delete a file.

graphics/f12ln07.jpg

Incorrect:
Private Sub DeleteAccountingBatchFile(ByVal strBatchFile _                                       As String)    ' Purpose   :  Delete the accounting batch file specified by     '              the user.    ' Physically delete the file.    System.IO.File.Delete(strBatchFile) End Sub 
Correct:
Private Sub DeleteAccountingBatchFile(ByVal strBatchFile _                                       As String)    ' Purpose   :  Delete the accounting batch file specified by     '              the user.    ' Get confirmation before deleting the file     If MessageBox.Show("Delete the file: " & strBatchFile & "?", _          "Confirm Deletion", MessageBoxButtons.YesNo, _          MessageBoxIcon.Question, _          MessageBoxDefaultButton.Button2) = DialogResult.Yes Then        ' Physically delete the file.       System.IO.File.Delete(strBatchFile)    End If End Sub 


Practical Standards for Microsoft Visual Basic. NET
Practical Standards for Microsoft Visual Basic .NET (Pro-Developer)
ISBN: 0735613567
EAN: 2147483647
Year: 2005
Pages: 84

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net