Chapter 11. Files and Serialization

Almost every program at some point must interact with files or persisted data in some way. The foundation of nearly all such functionality is located in the System.IO namespace.

Create, Read, and Write Files

There are generally two modes to access files: text and binary. In text mode, the raw contents of a file are converted to System.String for easy manipulation in .NET. Binary files are just that—you get access to the raw, unfiltered bytes, and you can do what you want with them. We’ll look at two simple programs that examine each type of file.

Most I/O in .NET is handled with the concept of streams, which are conceptual buffers of data that you can read from and write to in a linear fashion. Some streams (such as files) allow you to jump to an arbitrary location in the stream. Others (such as network streams) do not.

Create, Read, and Write a Text File

Solution: If you tell .NET that you are opening a text file, the underlying stream is wrapped in a text decoder called StreamReader or StreamWriter that can translate between UTF-8 text and the raw bytes.

Here is a sample program that writes its command-line arguments to a text file that you specify and then reads it back:

image

Note

For this and all succeeding code examples in this chapter, make sure you have using System.IO; at the top of your file, as it will not always be explicit in every code sample.

Note

Files are shared resources, and you should take care to close them when done to return the resource back to the operating system. This is done using the Dispose Pattern, which is described in Chapter 22, “Memory Management.” The using statements in the preceding code sample ensure that the files are closed at the end of each code block, regardless of any exceptions that occur within the block. You should consider this a best practice that you should always follow whenever possible.

Create, Read, and Write a Binary File

Solution: When you open files in binary mode, you get back a stream that you can control more precisely than with text. Here is very naive file copy program, but it demonstrates the point:

image

image

Delete a File

Solution: The File class has a number of static methods you can use, one of them being Delete().

File.Delete("Filename.txt");

Note

If the file does not exist, no exception will be thrown. However, DirectoryNotFoundException is thrown if the directory does not exist.

Combine Streams (Compress a File)

Solution: You can combine streams to accomplish rich behavior that can perform powerful transformations. Listing 11.1 shows a quick-and-dirty file compression utility.

Listing 11.1 CompressFile.cs

image

image

image

Get a File Size

Solution: The FileInfo class encapsulates data from the file system.

image

The FileInfo class contains many useful properties, such as creation and modification times, the directory, and file attributes such as hidden and archive in the Attributes property (an enumeration of FileAttributes).

Get File Security Description

Solution: The System.Security namespace contains .NET classes related to security. The following code sample display security information about a file whose name is passed on the command line.

image

image

You can run the program from the command line like this:

image

It produces output similar to the following:

image

Check for File and Directory Existence

Solution: This snippet uses the static Exists() methods on File and Directory to check for existence:

image

Enumerate Drives

Solution: The DriveInfo class provides static methods to retrieve this information.

image

This code produces the following output on my system (edited to show only unique drives):

image

Enumerate Directories and Files

Solution: DirectoryInfo can retrieve a list of subdirectories and files inside of it.

image

Note

Be aware that you can easily get a SecurityException while enumerating files and folders, especially if you’re not running as an administrator.

Browse for Directories

Solution: Use the FolderBrowserDialog class in System.Windows.Forms. This example is from the BrowseForDirectories project in the sample code for this chapter.

image

Note

There is no WPF-equivalent of this dialog, but you can use it from WPF as well.

Search for a File or Directory

Solution: The DirectoryInfo object contains many useful functions, among them the ability to search the file system for files and folders containing a search pattern. The search pattern can contain wildcards, just as if you were using the command prompt.

Listing 11.2 provides a simple example that searches a directory tree for any file or directory that matches the input pattern.

Listing 11.2 Searching for a File or Directory

image

image

image

image

Here’s the program output (your results will likely vary):

image

Note

You may get an “access denied” error while running this program when the search runs across a folder you don’t have permission to access. One way to handle this is to change the search options to SearchOption.TopDirectoryOnly, track the subdirectories in a stack, and perform the recursive search yourself, handling the possible exceptions along the way.

Manipulate File Paths

Solution: You should almost never need to manually parse a path in C#. Instead, use the System.IO.Path class to perform your manipulation. This class has only static methods.

Table 11.1 details most of the methods and properties available to you.

Table 11.1 Path Methods and Properties

image

There are two additional useful methods. Path.Combine() will take two or more strings and combine them into a single path, inserting the correct directory separator characters where necessary. Here’s an example:

string path = Path.Combine(@"C:Windows", "System32", "xcopy.exe ");

This results in the path having the value "C:WindowsSystem32xcopy.exe ".

The second method, Path.ChangeExtension(), does just what you think it would. Here’s an example:

image

The new value of path is "C:WindowsSystem32xcopy.bin". Note that this does not change the file on the disk—it’s just in the string.

Create Unique or Temporary Filenames

Solution: Rather than trying to figure out where the user’s temporary directory is, generating a random filename, and then creating a file, you can just use the following:

image

On one run on my system, GetTempFileName() produced the following value:

C:UsersBenAppDataLocalTemp mp96B7.tmp

If you don’t need the file to actually be created, you can get just a random filename (no path) by using the following:

string fileName = Path.GetRandomFileName();
//fileName: fup5cwk4.355

Watch for File System Changes

Solution: Many file systems provide ways for the operating system to notify programs when files and directories change. .NET provides the System.IO.FileSystemWatcher class to listen to these events.

image

image

Here’s some sample output (during a create, rename, and delete of the file temp.txt):

image

You can also call watcher.WaitForChange(), which will wait until something happens before returning, but usually the event-based mechanism will work for you.

Get the Paths to My Documents, My Pictures, Etc.

Solution: You should never hard-code the paths. Not only can different versions of the OS have different folder names, but the user can change these folders to be in whatever location he wants. Use Environment.GetFolder() with the Environment.SpecialFolder enumeration to retrieve the actual folder on the disk. The following code will print the entire list:

image

Note

In general, you should put your application’s data in the LocalApplicationData (nonroaming) or ApplicationData (roaming) folder. That is what these folders are meant for. Examine them on your own computer to see how other software uses them. You should never write program data to ProgramFiles or anywhere file security is an issue. The ApplicationData directory will be replicated on all computers to which the user logs on in a domain, so avoid putting unnecessary data there. Starting with Windows Vista, the operating system enforces file security much more strongly, and an application that doesn’t pay attention to security issues can break.

Serialize Objects

Solution: The easy way to allow a type to be serialized is to just put the attribute [Serializable] in front of the type definition. .NET provides three built-in serialization formatters: SOAP, binary, and XML. XML serialization is handled a little differently and will be discussed in its own chapter (see Chapter 14, “XML”). For the examples in this chapter, I chose SOAP because it can be represented in text. But you can easily substitute the BinaryFormatter class.

Serialize Objects Using SerializableAttribute

Let’s do this to our Vertex3d class from Chapter 2, “Creating Versatile Types.” For simplicity, I’ve created a simplified version of the struct for use here:

image

The following code can serialize and output it for us:

image

Here’s the output:

image

All of that, with no effort other than adding [Serializable]. Actually, not quite true. This version of Vertex3d doesn’t contain the int? _id field that was present in the original code. Serialization formatters don’t know what to do with that. If you want to be able to serialize classes that contain data that can’t be automatically formatted, you have to do a little more work, as you’ll see in the next section.

Serialize Objects by Implementing ISerializable

In order to serialize more complex data (often such as collections), you need to take control of the serialization process. We’ll do this by implementing the ISerializable interface and also defining a serializing constructor.

Modify the code from the previous section with the following additions:

image

image

Serialize to an In-Memory Stream

Solution: The preceding serialization example did this, but I’ll cover it in this section as well.

image

Store Data when Your App Has Restricted Permissions

Solution: Use Isolated Storage. This is kind of like a virtual file system that .NET associates with an assembly, user, application domain, application (when using ClickOnce only), or a combination of these items. By using Isolated Storage, you can give programs the ability to store information without giving them access to the real file system.

Here’s a simple example that creates a subdirectory and a text file:

image

image

After a few runs, the output looks like this:

image

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset