Sams Teach Yourself Visual C# 2005 in 24 Hours, Complete Starter Kit

The Registry is a handy place to store user options and program configuration settings. It's not a good place, however, to store a lot of data such as a text document. If you have a lot of text data to store and retrieve, a good old-fashioned text file is probably the best place to put it (assuming that a real database such as Microsoft SQL is not an option). Visual C# includes classes that makes it relatively easy to manipulate text files: StreamWriter and StreamReader. Notice that reading and writing text files are performed by two different objects, only one of which can access a file at any given time. If you want to simultaneously read and write to a single file, you're probably best off to use a real database.

Writing to a Text File

Writing to text files is done using the StreamWriter class. The first step to using this class is to declare an object of type StreamWriter, like this:

System.IO.StreamWriter objFile = new System.IO.StreamWriter(@"C:\test.txt");

Or like this:

System.IO.StreamWriter objFile = new System.IO.StreamWriter(@"C:\test.txt", true);

By the Way

There are actually seven different forms of StreamWriter usage. I'm showing you the most common, but if you're going to do serious work with text files, you should read the MSDN document on the StreamWriter class.

As you can see, the second parameter is optional, and it determines whether you want to append to the text file if it already exists. If you omit this second parameter, or supply false as its value, a brand-new text file is created. If the text file already exists, it gets replaced with a new file of the same name. If you pass true, as in the second example, the file is opened, and any write operations you perform on the file are tacked on to the end of the file.

Did you Know?

If you pass a file path/name that does not exist, Visual C# creates a new text file for you when you write data to the StreamWriter object.

After you have an object that points to a StreamWriter object, you can store data in the text file using one of the following two methods:

  • WriteLine() Sends a single line of text to the file and automatically appends a carriage return to the end of the line. Each call to WriteLine() creates a new line.

  • Write() Sends data to the file but does not automatically append a carriage return to create a new line.

These two methods are best understood by example. Consider the following code snippet:

System.IO.StreamWriter objFile = new System.IO.StreamWriter(@"C:\test.txt"); objFile.WriteLine("text1"); objFile.WriteLine("text2"); objFile.WriteLine("text3"); objFile.Close(); objFile.Dispose();

This snippet would produce the following data in the text file:

text1 text2 text3

By the Way

Notice the last statement: objFile.Close(). It's absolutely vital that you close a text file when you're finished with it, and the Close() method does this. In addition, you should also call objFile.Dispose() to make sure the file is fully released.

Now, consider the same code snippet that uses Write() instead of WriteLine():

System.IO.StreamWriter objFile = new System.IO.StreamWriter(@"C:\test.txt"); objFile.Write("text1"); objFile.Write("text2"); objFile.Write("text3"); objFile.Close(); objFile.Dispose();

This snippet produces a text file that contains the following:

text1text2text3

See how WriteLine() creates lines of data, while Write() simply streams the data into the file? This is an incredibly important distinction, and understanding the difference is crucial to your success writing text files. Which method you choose depends entirely on what you are trying to accomplish. I think perhaps that WriteLine() is the most common way. The following code illustrates how you could use WriteLine() to store a list of albums (assuming that you have the list in a list box titled lstAlbums):

System.IO.StreamWriter objFile = new System.IO.StreamWriter(@"C:\albums.txt"); for (int intCounter = 0; intCounter <= lstAlbums.Items.Count -1; intCounter++) { objFile.WriteLine(Convert.ToString(lstAlbums.Items[intCounter])); } objFile.Close(); objFile.Dispose();

Reading a Text File

Reading a text file is handled by the StreamReader class, which behaves similarly to the StreamWriter class. First, you need to define an object of type StreamWriter, like this:

System.IO.StreamReader objFile = new System.IO.StreamReader(@"C:\test.txt");

A key difference in declaring a StreamReader object versus a StreamWriter object is how the code behaves if the file is not found. The StreamWriter object is happy to create a new text file for you if the specified file isn't found. If the StreamReader can't find the specified file, it will throw an exceptionsomething you need to account for in your code.

Just as StreamWriter lets you write the data to the file in one of seven ways, StreamReader also has multiple ways to read the data. The first of the most common two ways is using the ReadToEnd() method, which reads the entire file and is used to place the contents of the file into a variable. You would use ReadToEnd() like this:

System.IO.StreamReader objFile = new System.IO.StreamReader(@"C:\test.txt"); string strContents; strContents = objFile.ReadToEnd(); objFile.Close(); objFile.Dispose(); MessageBox.Show(strContents);

The ReadtoEnd() method can be handy, but sometimes you just want to get a single line of text at a time. For example, consider the text file created by the previous example, the one with a list of albums. Say that you wanted to read the text file and place all the albums found in the text file into a list box named lstAlbums. The ReadToEnd() method would allow you to get the data, but then you would have to find a way to parse each album name. The proper solution for reading one line at a time is to use the ReadLine() method. The following code shows how you could load the Albums.txt text file, one line at a time, and place each album name in a list box:

System.IO.StreamReader objFile = new System.IO.StreamReader(@"C:\albums.txt"); string strAlbumName; strAlbumName = objFile.ReadLine(); while (strAlbumName != null) { lstAlbums.Items.Add(strAlbumName); strAlbumName = objFile.ReadLine(); } objFile.Close(); objFile.Dispose();

A couple of important concepts in this example need discussing. The first is how do you know when you've reached the end of a text file? The answer is that the return result will be null. So, the first thing this code does (after creating the StreamReader object and the string variable) is get the first line from the text file. It's possible that the text file could be empty, so the while loop tests for this. If the string is null, the file is empty, so the loop doesn't execute. If the string is not null, the loop begins. The first statement in the loop adds the string to the list box. The next statement gets the next line from the file. This sends execution back to the while statement, which again tests to see whether we're at the end of the file. One thing this code doesn't test for is a zero-length string (""). If there is a blank line in the text file, the string variable will hold a zero-length string. You might want to test for a situation like this when working with text files in your code.

That's it! Text files are not database files; you'll never get the power and flexibility from a text file that you would from a real database. With that said, text files are easy to work with and provide amazing and quick results within the context of their design.

Modifying Your Picture Viewer Project to Use a Text File

In this section, you're going to modify your Picture Viewer project to use a text file. What you'll be doing is have the Picture Viewer update a log (a text file) every time the user views a picture. You'll then create a simple dialog box that the user can open to view the log file. If you no longer have the Picture Viewer project open from earlier, open it now.

Creating the Picture Viewer Log File

In this section, you'll modify the Picture Viewer project to create the log file. Follow these steps to implement the log functionality:

1.

Double-click frmViewer.cs in the Solution Explorer window to display the form in the designer.

2.

Recall that you created a single procedure that is called from both the menu and the toolbar to open a picture. This makes it easier because you only have to add the log code in one place. Double-click the Open Picture button on the toolbar to access its Click event.

3.

You now need to go to the OpenPicture() function. Here's an easy way to do this: Right-click the code this.OpenPicture(); and choose Go To Definition from the shortcut menu (see Figure 20.5). Whenever you do this to a procedure call, Visual C# displays the code of procedure being referenced.

Figure 20.5. Go To Definition is a quick way to view a procedure being called in code.

4.

Now, take a look at the OpenPicture() procedure. Where would you place the code to create a log file? Would you enter all of the log file code right into this procedure? First, the log file should be updated only when a picture is successfully loaded, which would be in the try block, right after the statement that updates the sbrMyStatusStrip control. Second, the log code should be isolated from this procedure, so all you are going to add is a single function call. Add this statement at the end of but still in the try block:

UpdateLog(ofdSelectPicture.FileName);

Your code should now look like Figure 20.6.

Figure 20.6. It's always a good idea to isolate code into cohesive procedures.

5.

Now, position the cursor between the closing brace of OpenPicture() procedure and press Enter to create a new line and then enter the following procedure code:

private void UpdateLog(string strFileName) { System.IO.StreamWriter objFile = new System.IO.StreamWriter( System.AppDomain.CurrentDomain.BaseDirectory + @"\PictureLog.txt", true); objFile.WriteLine(DateTime.Now + " " + strFileName); objFile.Close(); objFile.Dispose(); }

Most of this code should be recognizable, but consider this snippet:

System.AppDomain.CurrentDomain.BaseDirectory + @"\PictureLog.txt"

The method BaseDirectory() returns the path of the running program. This is a great trick to know! What you've done here is append the filename PictureLog.txt to the application path, so that the log file is always created in the application path. This makes it easy for the user to find it. In a robust application, you might let the user specify a path, perhaps storing it in the Registry. For our purposes, the application path works just fine.

By the Way

When debugging an application in the Visual C# IDE, the application path might not be exactly what you expect. When you compile and test your application, Visual C# creates a bin\Debug folder under the folder containing your project. This is where it places the temporary .exe it creates for debugging, and this is your application path. If you go looking for the log file in your project folder, you won't find it. You need to drill down into the \bin\Debug folder to get it.

Displaying the Picture Viewer Log File

In this section, you'll modify the Picture Viewer project to include a dialog box that the user can display to view the log file. Follow these steps to implement the log viewer functionality:

1.

Choose Project, Add Windows Form from the menu to display the Add New Item dialog box. Enter frmLogViewer.cs for the new form name and click Add to create the form.

2.

Set the properties of the new form as follows:

Property

Value

Size

520,344

MaximizeBox

False

MinimizeBox

False

Text

Picture Viewer History Log

3.

Add a new button to the form and set its properties as follows:

Property

Value

Name

btnOK

Anchor

Bottom, Right

Location

425,275

Text

OK

4.

Add a new text box to the form and set its properties as follows:

Property

Value

Name

txtLog

Anchor

Top, Bottom, Left, Right

Multiline

True

Location

12,12

ReadOnly

True

Size

488,257

5.

Double-click the OK button to access its Click event, and enter the following statement:

this.Close();

6.

Add the code that actually displays the log. Double-click frmViewer.cs in the Solution Explorer and then double-click the form to access its Load event.

7.

Enter the following code into the Form_Load event:

try { System.IO.StreamReader objFile = new System.IO.StreamReader( System.AppDomain.CurrentDomain.BaseDirectory + @"\PictureLog.txt"); txtLog.Text = objFile.ReadToEnd(); objFile.Close(); objFile.Dispose(); } catch { txtLog.Text = "The log file could not be found."; }

This code is just like the code discussed earlier on reading text files. It uses ReadToEnd() to load the entire log into the text box. The whole thing is wrapped in a try block to handle the situation of there being no log file.

8.

All that's left is to add a button to the toolbar of the Picture Viewer to display the log. Double-click frmViewer.cs in the Solution Explorer to display the form in the designer.

9.

Click the toolstrip to select it, and then click the Items property in the Properties window.

10.

Click the build button in the Items property in the Property window to access the Items Collection Editor and then create a new button on the toolbar. Set the new button's properties as follows:

Property

Value

Name

tbbShowLog

Image

Log.ico (found on my website)

Text

View Picture Log

ToolTipText

View Picture Log

11.

Click OK to save the new button, and then double-click the new button on the toolbar and add the following code:

frmLogViewer objLog = new frmLogViewer(); objLog.ShowDialog();

Testing Your Picture Viewer Log

Save your project now and press F5 to run it. Follow these steps to test the project:

1.

Click the View Picture Log button on the toolbar to display the Picture Viewer History Log. Notice that the text box displays The log file could not be found. This means the TRy block worked!

2.

Click OK to close the Log Viewer form.

3.

Click the Open Picture button on the toolbar, browse to a picture file, and display it.

4.

Now, click the View Picture Log button again and notice that the log now displays a log entry (see Figure 20.7).

Figure 20.7. Text files make creating logs easy.

Категории