Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

C# Bible - Jeff Ferguson, Brian Patterson, Jason Beres

.pdf
Скачиваний:
64
Добавлен:
24.05.2014
Размер:
4.21 Mб
Скачать

Figure 24-6: The Delete( ) method of the FileInfo class shows the attributes of the deleted file.

Start a new C# console application and name this project mv, after the UNIX-based command of the same name. Listing 24-11 shows the application in its entirety.

Listing 24-11: File Move Implementation

using System; using System.IO; namespace mv

{

class Class1

{

static void Main(string[] args)

{

string [] cla = Environment.GetCommandLineArgs(); if (cla.GetUpperBound(0) == 2)

{

FileInfo fi = new FileInfo(cla[1]); fi.MoveTo(cla[2]);

Console.WriteLine("File Created : " + fi.CreationTime.ToString()); Console.WriteLine("Moved to : " + cla[2]);

}

else

Console.WriteLine ("Usage: mv <source file> <destination file>");

}

}

}

Figure 24-7 shows the output from your File Move utility.

Figure 24-7: Move files with the MoveTo method of the FileInfo class.

Note that in this example, the destination filename can be either a filename or a directory name. If a directory name is specified, the file is moved. If a filename is present, the file is renamed and/or moved. The MoveTo() method essentially incorporates copy and rename functions in one method.

Accessing the Registry

Registry access was rather burdensome with the Windows API. C# provides you with some class objects that enable you to read and write to and from the Registry with ease. Using the Registry provides several benefits over older methods, such as text-based INI files. Because the Registry is indexed, searching for keys is fast. The Registry is a structured "document," which allows for structured information, such as a database, just to name one type.

Reading Registry keys

Registry access functionality is contained within the Microsoft.Win32 namespace, so you need to include this namespace in all your projects by entering the following line at the top of your source code file:

using Microsoft.Win32;

To read a Registry key, you must use the RegistryKey object. To begin exploring this object, examine Listing 24-12, an application that retrieves two pieces of information from the Registry.

Listing 24-12: Retrieve the CPU Type and Speed from the Registry

using System;

using Microsoft.Win32;

namespace CPUInfo

{

class Class1

{

static void Main(string[] args)

{

RegistryKey RegKey = Registry.LocalMachine; RegKey = RegKey.OpenSubKey(

"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"); Object cpuSpeed = RegKey.GetValue("~MHz");

Object cpuType = RegKey.GetValue("VendorIdentifier"); Console.WriteLine("You have a {0} running at {1}

MHz.",cpuType,cpuSpeed);

}

}

}

When instantiating an instance of the RegistryKey, you set it equal to a member of the Registry class. The preceding example sets the RegistryKey object equal to the Registry.LocalMachine field, which enables you access to the HKEY_LOCAL_MACHINE base key. Table 24-3 contains a list of all public fields within the Registry class.

 

Table 24-3: Public Fields Within the Registry Class

Field

 

 

Description

ClassesRoot

ClassesRoot defines the types of documents and the properties associated with those types. This field starts in the Windows Registry from the key HKEY_CLASSES_ROOT.

CurrentConfig

CurrentConfig contains information pertaining to your computer's hardware. This field starts in the Windows Registry from the key HKEY_CURRENT_CONFIG.

CurrentUser

 

All preferences for the current user are stored here. This field starts

 

 

in the Windows Registry from the key HKEY_CURRENT_USER.

 

 

 

DynData

 

DynData.

LocalMachine

LocalMachine contains configuration information for the computer. This field starts in the Windows Registry from the key HKEY_LOCAL_MACHINE.

PerformanceData

The base key stores performance-related information about the different software components. This field starts in the Windows Registry from the key HKEY_PERFORMANCE_DATA.

Users

This base key contains information that will be applied to a default user's configuration. This field starts in the Windows Registry from the key HKEY_USERS.

After you establish your RegistryKey object, you call its OpenSubKey() method and provide the key that you want to open. In this particular case, you want to navigate to the HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\Central\Processor\0\ key and read two values from that key. Keep in mind that you must include double backslash characters in the string, so that they are not interpreted as an escape character.

After you open the subkey, issue the following two lines of code to retrieve the "~MHz" and "VendorIdentifier" values within that subkey:

Object cpuSpeed = RegKey.GetValue("~MHz");

Object cpuType = RegKey.GetValue("VendorIdentifier");

Now you have the values stored within the appropriate variables, so you can display the information on the screen. Test the program from a console window, as shown in Figure 24-8.

Figure 24-8: The RegistryKey class simplifies the reading of important information from the Registry.

Those of you running on multiple processor machines can obtain a list of all processors by enumerating the CentralProcessor key. You find a subkey within CentralProcessor for each CPU contained within your machine.

Writing Registry keys

Creating and writing Registry keys is also accomplished using the RegistryKey object. Several methods in the RegistryKey class are useful when writing keys. Table 24-4 describes the purpose of some of the more prevalent members.

 

Table 24-4: Common RegistryKey Members

 

 

 

 

 

 

Name

 

 

Type

 

Description

 

 

 

 

 

 

SubKeyCount

 

 

Property

 

This property retrieves a count of the subkeys

 

 

 

 

 

for the current key.

 

 

 

 

 

 

ValueCount

 

 

Property

 

This property retrieves a count of the number of

 

 

 

 

 

values for the current key.

 

 

 

 

 

 

Close

 

 

Method

 

This method closes the current key. If changes

 

 

 

 

 

have been made to the key, changes are flushed

 

 

 

 

 

to disk.

 

 

 

 

 

 

CreateSubKey

 

 

Method

 

This method creates a new subkey if one doesn't

 

 

 

 

 

exist, or opens the subkey if it does exist.

 

 

 

 

 

 

DeleteSubKey

 

 

Method

 

This method deletes a subkey. This method is

 

 

 

 

 

overloaded and contains a Boolean parameter

 

 

 

 

 

that allows an exception to be thrown if the key

 

 

 

 

 

cannot be found.

 

 

 

 

 

 

DeleteSubKeyTree

 

 

Method

 

This method deletes a subkey and all child

 

 

 

 

 

subkeys recursively.

 

 

 

 

 

 

DeleteValue

 

 

Method

 

This method deletes a value from a key. This

 

 

 

 

 

method is overloaded and contains a Boolean

 

 

 

 

 

parameter that allows an exception to be thrown

 

 

 

 

 

if the value is missing.

 

 

 

 

 

 

GetSubKeyNames

 

 

Method

 

This method returns a string array containing all

 

 

 

 

 

subkey names.

 

 

 

 

 

 

GetValue

 

 

Method

 

This method retrieves a value for a specific key.

 

 

 

 

 

This method is overloaded and contains a

 

 

 

 

 

parameter that permits a default value. If the

 

 

 

 

 

value for a key is not found, the default value

 

 

 

 

 

you specify will be returned.

 

 

 

 

 

 

GetValueNames

 

 

Method

 

This method returns a string array containing all

 

 

 

 

 

values for the specified key.

 

 

 

 

 

 

OpenSubKey

 

 

Method

 

This method opens a subkey for processing

 

 

 

 

 

(read/write access).

 

 

 

 

 

 

SetValue

 

 

Method

 

This method sets a value for a key. To set the

 

 

 

 

 

default value for a key, set the subKey

 

 

 

 

 

parameter to an empty string.

 

 

 

 

 

 

Caution Writing values can be dangerous and can cause your system to become unresponsive if care is not taken. Double-check all code before testing any application that writes values to the Registry.

Listing 24-13 shows a simple application that writes two values to the Registry and then reads those values back in to display them.

Listing 24-13: Write a Text and DWord Value to the Registry

using System;

using Microsoft.Win32;

namespace WriteRegValues

{

class Class1

{

static void Main(string[] args)

{

RegistryKey RegKeyWrite = Registry.CurrentUser; RegKeyWrite = RegKeyWrite.CreateSubKey

("Software\\CSHARP\\WriteRegistryValue");

RegKeyWrite.SetValue("Success","TRUE");

RegKeyWrite.SetValue("AttemptNumber",1);

RegKeyWrite.Close();

RegistryKey RegKeyRead = Registry.CurrentUser; RegKeyRead = RegKeyRead.OpenSubKey

("Software\\CSHARP\\WriteRegistryValue");

Object regSuccessful = RegKeyRead.GetValue("Success");

Object regAttemptNumber = RegKeyRead.GetValue("AttemptNumber"); RegKeyRead.Close();

if ((string)regSuccessful == "TRUE")

Console.WriteLine("Succeeded on attempt # {0}",regAttemptNumber); else

Console.WriteLine("Failed!");

}

}

}

After you create a RegistryKey object, you can create a new subkey with the CreateSubKey() method. Ensure that when using this method, you use double backslash characters, so the compiler doesn't interpret the characters as an escape sequence. In this example, you are creating a new key under HKEY_CURRENT_USER. Store your values in the \Software\CSHARP\WriteRegistryValue subkey.

With the new key in place, use the SetValue() method to specify the name of the value and the actual value. This example, stores text in the Success value and a DWord in the AttemptNumber value. After the values are set, it's best to close the key in case of a power outage or similar failure. At this point, the changes have been committed to the Registry. If you open RegEdit and navigate to the proper key, you should see the values shown in Figure 24-9.

Figure 24-9: RegEdit reveals that your values have been saved.

As with the previous example, you now create a new RegistryKey object and read the values back in. If the Success value is in fact True, you display the information on the screen, as shown in Figure 24-10.

Figure 24-10: Keys read from the Registry are displayed on the console.

This application demonstrates a simple technique for writing values to the Registry. This method would prove useful for keeping track of program settings, recording the last position and size of your applications interface, and so on. The possibilities are endless.

Enumerating Registry keys

Enumerating Registry keys is a lot like the Find Files feature in Windows. It enables you to scan from any point in the Registry and retrieve all subkeys and values below that starting point.

No methods are currently incorporated into .NET to enumerate Registry keys; it is up to you to build functions to support your needs. Knowing the structure of the keys you want to enumerate makes things much easier, as you can simply use a loop. If the structure of the Registry entries is unknown, you have to create a function that can call itself and pass the starting key in each time it is called.

Listing 24-14 is an example of enumerating Registry keys. In this example, you scan the Registry for a list of all software installed on the computer. This program lists any application that shows up in the Add/Remove section of the Control Panel.

Listing 24-14: Enumerating Registry Keys

using System;

using Microsoft.Win32;

namespace Installed

{

class Class1

{

static void Main(string[] args)

{

RegistryKey myRegKey=Registry.LocalMachine; myRegKey=myRegKey.OpenSubKey

("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"); String [] subkeyNames = myRegKey.GetSubKeyNames(); foreach (String s in subkeyNames)

{

RegistryKey UninstallKey=Registry.LocalMachine; UninstallKey=UninstallKey.OpenSubKey

("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + s); try

{

Object oValue=UninstallKey.GetValue("DisplayName"); Console.WriteLine(oValue.ToString());

}

catch (NullReferenceException)

{

}

}

}

}

}

After you have created a RegistryKey object, you open the Uninstall subkey, which contains a list of all programs installed. From here, you use GetSubKeyNames, which returns a string array of all subkeys. Now that you have your list of subkeys, you use the foreach operator to iterate through all elements in your subkey string array.

When you iterate through each key, you search for a value called DisplayName. This DisplayName value is the name that is shown in the Add/Remove Programs section of the Control Panel. Remember that not all keys will have this value. Therefore, you must encapsulate your GetValue method with a try..catch statement to catch any exceptions that may occur. After a DisplayName value is found, you retrieve the value and display it on the screen. The foreach statement then moves on to the next Registry key contained in the string array.

Press F5 to try the application. You'll probably see a long list of applications scroll by as the program scans the Registry (see Figure 24-11).

Figure 24-11: Scan all installed applications with a Registry enumerator.

One thing that you did not tackle in this program is arranging the applications alphabetically. The items in the Registry are not stored in this manner, but to overcome this, you could simply store the results within a string array and call the Sort method to arrange the output in any manner allowed.

Summary

The .NET Framework has greatly reduced the amount of code and time it takes to effectively deal with files and the Windows Registry. Among the many benefits that the .NET Framework, you now have access to components such as the FileSystemWatcher which enables you to watch a file system for changes made to any file. You must take care, however, when writing applications that deal with the Windows Registry because accidentally removing Registry keys can cause your system to become unstable or even inoperable.

Chapter 25: Accessing Data Streams

In This Chapter

The .NET Framework ships with classes that provide a high level of support for reading and writing data. Traditionally, languages have provided built-in support for reading and writing to disk-based files, and have relied on operating system programming interfaces to provide support for reading and writing to other types of data streams, such as network sockets or memory-based files. The .NET Framework unifies data I/O by providing a common set of classes that support data reads and writes regardless of the underlying storage mechanism used to provide the data access. All of these classes can be used from C# code.

In this chapter, you learn to use streams. You learn how to use readers and writers to read data from and write data to a stream and how to perform file operations in the background.

Understanding the Data I/O Class Hierarchy

Figure 25-1 illustrates the class hierarchy for the basic .NET Framework classes used in data I/O work. The classes are grouped into one of three categories: streams, writers, and readers.

Figure 25-1: Data I/O class hierarchy

Using streams

Stream classes provide a mechanism for referring to a data container. Stream classes share a common base class called Stream, which is defined in a .NET Framework namespace called System.IO. The Stream base class contains properties and methods that enable callers to work with the data stream.

The .NET Framework ships with several classes that derive from the base Stream class. Each class provides a specific implementation of a data stream used for a particular environment. The FileStream class, for example, provides an implementation that enables callers to work with streams of data tied to a disk-based file. Similarly, the NetworkStream class provides an implementation that enables callers to work with streams of data accessed over a network.

Using writers

Streams support data access at the byte level. They include methods called Read() and Write(), which work with an array of bytes that are processed during the call. However, working at the byte level might not be ideal for your application. Suppose, for example, that your application needs to write a series of integers to a stream. Because integers in the 32-bit implementation are four bytes wide, your C# code would need to translate each integer into a string of four bytes that could be used in a call to the stream's implementation of Write(). The

.NET Framework includes writer classes that support writing various higher-level data types to a stream. A writer might support many overloads of a Write() method. For example, a write can accept such data types as int, long, or double. The writer class implementations translate the data type into a series of bytes and pass that translated byte stream to a Stream object. This class design frees your code from having to deal with streams at the byte level. Your C# application code can simply state, "write this unsigned long into the stream," for example, and enable the writer class to do the work needed to get the value stored into the stream as a series of bytes.

Using readers

Reader classes complement the writer classes. Like the writer classes, reader classes provide support for reading data types that transcend the simple byte array support offered by stream classes. A matching reader class complements each writer class in the .NET Framework.

Reader classes provide several overloads of a Read() method that enables your application code to read several types of data, such as strings, integers, longs, and so on.

Working with Streams

Streams support two methods of I/O:

Synchronous I/O, in which method calls that perform stream I/O do not return to the caller until the requested I/O operation is complete

Asynchronous I/O, in which method calls that perform stream I/O return before the requested operation is complete and notify the caller about the operation's completion at a later time

Understanding synchronous I/O

Listing 25-1 illustrates synchronous stream I/O. It creates a file and writes 256 bytes of binary data into the file. It then reads the 256 bytes back from the file and ensures that the data read matches the data written.

Listing 25-1: Synchronous File I/O

using System; using System.IO;

class FileTestClass

{

private

FileStream

BinaryFile;

private

byte []

ByteArray;

public FileTestClass()

{

Соседние файлы в предмете Программирование