Archive

Archive for the ‘C# .NET’ Category

C# .NET Tutorial 9: Regular Expression in C#

January 15, 2009 scerrimark 1 comment

The last post was dedicated to regular expressions. In this tutorial of the C# Tutorial series I am going to discus how you can use regular expressions in C#.

Using Regular Expressions for Pattern Matching

To help you understand let’s create a console application that accepts two strings as input and determines whether the first string, which is a regular expression, matches the second string. The console application must use the System.Text.RegularExpressions namespace. The check will be performed using the Regex.IsMatch static method. Here is the code.

using System.Text.RegularExpressions;

namespace TestRegExp
{
    class Class1
    {
        [STAThread]
        static void main (string[] args)
        {
            if (Regex.IsMatch(args[1], args[0])
                Console.WriteLine("Input matches regular expression.");
            else
                Console.WriteLine("Input does not match regular expression.");
        }
    }
}

To test it give it the following data:

  • ^\d{5}$ 1234 – should not match.
  • ^\d{5}$ 12345 – should match.

How to Specify Regular Expression Options

You can modify a regular expression pattern with options that affect matching behaviour. Regular expression options can be set by specifying the options parameter in the Regex(pattern, options) constructor, where options is a bitwise or combination of RegexOptions enumerated values. The following are the members of the RegexOptions enumeration:

  • None – no options are set.
  • IgnoreCase – Specifies case-insensitive matching.
  • MultiLine – matching is performed from the beginning to the end of each new line not from the beginning to the end of the string.
  • ExplicitCapture – specifies that only valid captures are explicitly named.
  • Compiled – specifies that the regular expression will be compiled to an assembly. It will generate Microsoft intermediate language code (MSIL) for the regular expression. This yields faster execution at the expense of start up time.
  • SingeLine – specifies single-line mode. This changes the meaning of the character (.) so that it matches every character (instead of every character except \n).
  • IgnorePatternWhitespace – specifies that unescaped white space is excluded from the pattern, and enables comments following a number sign (#).
  • RightToLeft – the search moves from right to left. With such an option the starting position in a regular expression should be specified at the end of the string instead of the beginning).
  • ECMAScript – specifies that ECMAScript – compliant behaviour is enabled for the expression. This option can only be used in conjunction with IgnoreCase and MultiLine flags. Other options will throw an exception.
  • CultureInvariant – specifes that cultural differences in language are ignored.

How to Extract Matched Data

Besides determining whether a string matches a pattern one can also extract information from a string. For example if you have the url www.markscerri.com and you only want the part between the www. and the .com you can extract it with a regular expression. To do this you need to:

  • Create a regular expression and enclose in parentheses the pattern to be matched.
  • Create an instance of the System.Text.RegularExpressions.Match class using the static method Regex.Match.
  • Retreive the matched data by accessing the elements of the Match.Groups array.

Here is an example:

string input = "www.markscerri.com";
Match m = Regex.Match(input, @"www.(\w+).com");
Console.WriteLine(Match.Groups[1]); //note that matches start from 1

The following example searches an input string and prints out all the href=”…” values and their locations in the string.

void GetHrefs(string input)
{
    Regex r;
    Match m;

    r = new Regex("href\\s*=\\s*(?:\"(?[^\"]*)\"|(?\\S+))", RegexOptions.IgnoreCase | RegexOptions.Compiled);
    for (m = r.Match(input); m.Success; m=m.NextMatch())
    {
        Console.WriteLine("Found href " + m.Groups[1] + " at " + m.Groups[1].Index);
    }
}

You can also use the Match.Result method to reformat extracted substrings. For example the following code extracts the protocol and port from a url. That is http://www.markscerri.com:8080/ will result in the string http:8080.

String Extractor(String url)
{
    Regex r = new Regex(@"^(?
\w+)://[^/]+?(?
:\d+)?/",RegexOptions.Compiled);
    return r.Match(url).Result("${proto}${port}");
}

How to Replace Substrings using Regular Expressions

You can use regular expressions to make replacements that are more complex than you can do with String.Replace. The following code uses the Regex.Replace static method to replace dates in mm/dd/yy format to dd-mm-yy format.

String ChangeFormat(String input)
{
    return Regex.Replace(input, "\\b(?\\d{1,2})/(?\\d{1,2})/(?\\d{2,4})\\b",
        "${day}-${month}-${year}");
}

In this example we use back references within regular expressions. The replacement expression ${day} inserts the substring captured by the group (?…).

Character escapes and substitutions are the only special constructs recognized in a replacement pattern. For example the replacement pattern a*${txt}b inserts the string a*, followed by the substring matched by the txt capturing group, followed by the string b. The * character is not recognized as a meta character within a replacement pattern.

The following list shows how to define named and numbered replacement patterns:

  • $number – substitutes the last substring matched by the group number number.
  • ${name} – substitutes the last substring matched by a (?<name>) group.
  • $$ – substitutes a single $ literal.
  • $& – substitutes a copy of the entire match itself.
  • $` – substitutes all the text of the input string before the match.
  • $’ – substitutes all the text of the input string after the match.
  • $+ – substitutes the last group captured.
  • $_ – substitutes the entire input string.

Validating Names with Regular Expressions

Regular expressions can be efficiently used to validate user input. However certain input such as names can be very difficult to validate because a name can have a lot of different valid strings. The following regular expression can be used to validate names and surnames:

[a-zA-Z'`-À,Â\s]{1,40}

Well that’s it for today. In the next tutorial I will be discussing encoding and decoding of strings. Until then enjoy!!


Categories: C# .NET

C# .NET Tutorial 8: Working with Isolated Storage

January 8, 2009 scerrimark 2 comments

Welcome to number 8 of this C# tutorial series. Today we will discuss working with isolated storage. With the emergence of viruses, malware, and spyware developers know that applications working in a sandbox of limited access is better for users. However applications sometimes need to store state data and this represents a problem for applications running on restricted priveleges. It would be nice if we had a place where applications can store information that is safe to use without having to test whether the application has enough rights to save data to the hard drive. The .NET Framework provides a solution for this. This is isolated storage. With isolated storage an application can save data without having to worry whether it is running in partial, limited, or full trust.

IsolatedStorageFile Class

The IsolatedStorageFile class provides the mechanism to create files and folders in isolated storage. These are the most important static methods of this class:

  • GetMachineStoreForApplication – retrieves a machine-level store for the called Click-Once application.
  • GetMachineStoreForAssembly – retrieves a machine-level store for the assembly that called.
  • GetMachineStoreForDomain – retrieves a machine-level store for the AppDomain within the current assembly that called.
  • GetStore – retrieves stores based on the IsolatedStorageScope enumerator.
  • GetUserStoreForApplication – retrieves a user-level store for the called Click-Once application.
  • GetUserStoreForAssembly – retrieves a user-level store for the assembly that called.
  • GetUserStoreForDomain – retrieves a user-level store for the AppDomain within the current assembly that called.

The following are the most important IsolatedStorageFile properties:

  • ApplicationIdentity – The Click-Once application’s identity that scopes the isolated storage.
  • AssemblyIdentity – The assembly’s identity that scopes the isolated storage.
  • CurrentSize – the size of the current data stored in the isolated storage.
  • MaximumSize – the maximum storage size of the isolated storage.
  • DomainIdentity – the identity of the AppDomain that scopes the isolated storage.
  • Scope – the IsolatedStorageScope enumeration value that describes the scope of this isolated storage.

These are the commonly used IsolatedStorageFile methods:

  • Close – closes an instance of the store.
  • CreateDirectory – creates a directory within the store.
  • DeleteDirectory – deletes a directory within the store.
  • DeleteFile – deletes a file within the store.
  • GetDirectoryNames – gets a list of directory names within the store that match a file mask.
  • GetFileNames – gets a list of file names within the store that match a file mask.
  • Remove – removes the entire store from the current system.

Note: Click-Once applications are new types of applications (in .NET 2.0) that are meant to be deployed and installed from web pages. These new type of applications are meant to solve deployment of applications across a large company. For more info click here.

How to Create a Store

Before saving data in isolated storage one needs to determine the scope for the data in the store. For most applications you normally choose one of the following two methods:

  • Assembly/Machine – this method creates a store to keep information that is specific to the calling assembly and the local machine. It is well suited for application-level data.
  • Assembly/User – this method creates a store to keep information that is specific to the calling assembly and the current user. It is well suited for user-level data.

To create one of the following you use the following code:

//Assembly/Machine store
IsolatedStorageFile myStorage = IsolatedStorageFile.GetMachineStoreForAssembly();

//Assembly/User store
IsolatedStorageFile myStorage = IsolatedStorageFile.GetUserStoreForAssembly();

For Click-Once deployed applications one can use an application-level store that supports both a machine-level store and a user-level store. This only works with Click-Once applications because the executing assembly has its own evidence that might or might not be valid for local applications.

IsolatedStorageFileStream Class

The IsolatedStorageFileStream encapsulates a stream that is used to create files in isolated storage. It derives from the FileStream class and therefore its properties and methods are the same.

Reading and Writing data to Isolated Storage

To create data within isolated storage you do it through the IsolatedStorageFileStream class. You create a new instance of the class specifying a relative file name and a store. Here is the  code.

//create a store
IsolatedStorageFile myStorage = IsolatedStorageFile.GetUserStoreForAssembly();
//create an isolated storage file stream
IsolatedStorageFileStream userStream = new IsolatedStorageFileStream("UserSettings.dat", FileMode.Create, userStore);

Working with the IsolatedStorageFileStream is just like working with any other stream. The following code provides an example.

//wrap IsolatedStorageFileStream to a StreamWriter
StreamWriter writer = new StreamWriter(userStream);
writer.WriteLine("UserName = Mark");
writer.Close();

Reading is also done in a very similar way. The only difference is that you need to change the FileMode to Open as shown here.

IsolatedStorageFileStream userStream = new IsolatedStorageFileStream("UserSettings.dat", FileMode.Open, userStore);

The only difference from the other streams is that the Isolated Storage does not support checking for the existing of files directly like File.Exists. To do this you need to use the following code:

string[] files = userStore.GetFileNames("UserSettings.dat");
if (files.length == 0)
    Console.WriteLine("File not found");
else
    Console.WriteLine("File found");

How to use Directories in Isolated Storage

In isolated storage one can also create directories as shown in this code:

userStore.CreateDirectory("TestDirectory");

IsolatedStorageFileStream userStream = new IsolatedStorageFileStream(
                                                                      @"TestDirectory/UserSettings.dat",FileMode.Create, userStore);

To check for existence of directories you need to use the following code:

string[] directories = userStore.GetDirectoryNames("TestDirectory");
if (directories.length == 0)
{
    //directory not found
}
else
{
    //
}

The IsolatedStorageFilePermission Class

The IsolatedStorageFilePermission class encapsulates the permission that can be granted to code to allow it to access isolated storage. The following are the important properties:

  • UsageAllowed – gets or sets the type of usage allowed.
  • UserQuota – gets or sets the overall size of storage allowed per user.

Isolated Storage and Permissions

Before an assembly or application uses the isolated storage it needs the necessary permissions. Demanding permission can be accomplished by annotating your class or method with the IsolatedStorageFilePermission as shown here.

[IsolatedStorageFilePermission(SecurityAction.Demand)]
class Example
{
}

This ensures that any calls to work with isolated storage within this class willl succeed. This permission also supports several attributes that can be used to modify how isolated storage is used as shown below.

[IsolatedStorageFilePermission(SecurityAction.Demand, UserQuota=1024, UsageAllowed=IsolatedStorageContainment.AssemblyIsolataionByUser)]
class Example
{
}

Well that’s all for today! In the next two tutorials we will focus on text, specifically searching, modifying, and encoding text. In the next tutorial we will turn our attention to regular expressions in C#. See you soon!

Categories: C# .NET

C# .NET Tutorial 7: Compressing Streams

January 7, 2009 scerrimark Leave a comment

By now you have got used to the C# tutorials. If not you can view all of them here. This tutorial will focus on stream classes that support compression of data. In the .NET Framework there are two such streams.

In the I/O system of the .NET Framework that are two method of compressing data: GZIP and DEFLATE. Both these compression algorithms are industry-standard and are limited to compression of uncompressed data up to 4GB. These compression methods are exposed in two streams: GZipStream, and DeflateStream classes.

GZipStream Class and the DeflateStream Class

The functionality of these two classes is identical. The only difference is the compression algorithm that they use. Here are the important properties of these classes:

  • BaseStream – gets the underlying stream.
  • CanRead – determines whether the stream supports reading while decompressing a file.
  • CanWrite – determines whether the stream can be written to.
  • CanTimeout – determines whether the stream can timeout.
  • CanSeek – determines whether the stream supports seeking.
  • Length – this is inherited from the Stream class however do not use it with these classes because it will throw a NotSupportedException
  • Position – this is inherited from the Stream class however do not use it with these classes because it will throw a NotSupportedException
  • ReadTimeout – gets or sets the stream’s time out for read operations.
  • WriteTimeout – gets or sets the stream’s time out for write operations.

The following are the most commonly used methods:

  • Close – closes the streams and any other resources associated with it.
  • Flush – clears any buffers within the stream and forces any changes to be written to the underlying system or device.
  • Read – performs a sequential read of a specified number of bytes and then moves the cursor accordingly.
  • ReadByte – reads a single byte and moves the cursor by one.
  • Write – writes a specified number of bytes of data to the stream and updates the cursor to reflect the new write position.
  • WriteByte – writes a single byte to the stream and updates the position.
  • Seek – Not implemented. It will throw a NotSupportedException.
  • SetLength – Not implemented. It will throw a NotSupportedException.

How to Compress Data with a Compression Stream

Compression streams are a little different than the other streams. Instead of the stream writing to a resource such as a file or memory, the compression streams write to another stream. The compression streams take in data like any other stream. But then it writes it in compressed format to another stream. The following example demonstrates how to compress a file and write a new compressed version.

//first we need to open the file and create a new file for the compressed version
FileStream sourceFile = File.OpenRead(@"C:\data.bak");
FileStream destFile = File.Create(@"C:\data.gzip");

//now we need the compression stream to wrap the outgoing stream
GZipStream compStream = new GZipStream(destFile, CompressionMode.Compress);

//all we need to do now is write from the source file to the compression stream
int aByte = sourceFile.ReadByte();
while (aByte != -1)
{
    compStream.WriteByte((byte)aByte);
    aByte = sourceFile.ReadByte();
}

Note that we never wrote in the destination file. Because we are writing in the compression stream, the compression stream will write the compressed version in the destination file. Also if you want to use the Deflate algorithm all you need to do is change the compression stream to the DeflateStream.

How to Decompress Data with a Compression Stream

Here is the code used for decompression.

//Like before we need to declare a source file and a destination file. But now the source file is the compressed version.
FileStream sourceFile = File.OpenRead(@"C:\data.gzip");
FileStream destFile = File.Create(@"C:\data.bak");

//Now the change comes in the compression stream algorithm. We will wrap the source file and we will used the Decompress mode
GZipStream decompStream = new GZipStream(sourceFile, CompressionMode.Decompress);

//Now we need to read from the compression stream (not the source file) and write to the destination file
int aByte = decompStream.ReadByte();
while (aByte != -1)
{
    destFile.WriteByte((byte)aByte);
    aByte = decompStream.ReadByte();
}

So you now know how to compress and decompress streams. What’s next? In the next tutorial I will show you how to work with isolated storage. With isolated storage, data is always isolated by user and by assembly. Until then enjoy!!

Categories: C# .NET

C# .NET Tutorial 6: Reading and Writing Files

January 5, 2009 scerrimark Leave a comment

In the last couple of week I have been writing a number of C# tutorials. This is number 6 and today we will discuss reading and writing of files, two very common tasks in development. For those who are new the previous 5 tutorials can be found here.

Streams

Streams are used to write and read both sequential and random access data. These are the common properties of the Stream class in .NET:

  • CanRead – determines whether stream supports reading.
  • CanSeek – determines whether stream supports seeking.
  • CanTimeout – determines whether stream supports time out.
  • CanWrite – determines whether stream supports writing.
  • Length – returns the length in bytes of the stream.
  • Position – gets or sets the cursor to determine where in the stream the current position is.
  • ReadTimeout – gets or sets the stream’s time out for read operations.
  • WriteTimeout – gets or sets the stream’s time out for write operations.

The following are the Stream common methods:

  • Close – closes the stream and releases any associated resources with it.
  • Flush – clears any buffers within the stream and forces any changes to the stream to be written to the underlying system or device represented by the stream.
  • Read – performs a sequential read from the current position of a number of bytes and updates the position to the end of the read bytes.
  • ReadByte – reads one byte and updates the position by one.
  • Seek – sets the position within the stream.
  • SetLength – specifies the length of the stream.
  • Write – writes information to the stream as number of bytes and updates the current position to reflect the new write position.
  • WriteByte – writes a single byte to the stream and updates the position by one.

All the stream classes in .NET derive from the Stream class. These include:

  • FileStream (System.IO)
  • MemoryStream (System.IO)
  • CryptoStream (System.Security)
  • NetworkStream (System.Net)
  • GZipStream (System.Compression)

The reason these streams have the same base class is that working with data as a flow is a common way in different scenarios. Let’s start looking at some examples how to work with a stream. Learning to work with a stream means that you can apply that knowledge to any type of stream. To dump the contents of a stream on screen you use the following code:

//make sure we read from the beginning
theStream.Position = 0;
//Go through the entire stream and read byte by byte
while (theStream.Position != theStream.Length)
{
    Console.WriteLine("{0:x2}", theStream.ReadByte());
}

This code is able to work on any kind of stream. The next example is to send information to a stream:

theStream.Position = theStream.Length; //puts cursor at the end
theStream.Write(data, 0 , data.Length);

Classes for Reading and Writing data

A number of classes take part in the process of reading and writing files. One of these is the File class. This classes exposes static methods used for opening and creating classes. The File class can perform:

  • Atomic operations to read and write to files.
  • Operations to open files for reading or writing.
  • Simple file operations (File.Exists, File.Delete, etc.).

The File class can return a number of types with the FileStream being the most rudimentary. The File Class also has methods that return objects of type StreamReader and StreamWriter.These classes wrap a FileStream to support sequential reading and writing to a stream.

The File operations supported by the File Class are the same as the FileInfo class.

The MemoryStream is a special stream for manipulating data in memory. This stream is used to create stream objects in memory for optimization.

File Class

The File class is used to handle file streams for reading and writing. These are the most important File static methods:

  • AppendAllText – appends a string to a file. If the file does not exist it creates it.
  • AppendText – Opens a file and returns a StreamWriter that is prepared to allow text to be added to the file.
  • Copy – copies a file to a new file. The new file must not exist for Copy to be successful.
  • Create – creates a new file and returns a FileStream.
  • CreateText – creates or opens a file and returns a StreamWriter ready to have text written to it.
  • Move – moves a file from one place to another.
  • Open – opens an existing file and returns  FileStream object.
  • OpenRead – opens an existing file and returns a read-only FileStream object.
  • OpenText – opens an existing file and returns a StreamReader object.
  • OpenWrite – opens an existing file for writing and returns a StreamWriter object.
  • ReadAllBytes – opens a file, reads the content to a byte array, and closes the file in one atomic operation.
  • ReadAllLines – opens a file, reads the content line by line into an array of strings and closes the file in one atomic operation.
  • ReadAllText – opens a file, reads the content into a string, and closes the file in one atomic operation.
  • WriteAllBytes – opens a file, writes the content of a byte array in it, and closes the file in one atomic operation.
  • WriteAllLines – opens a file, writes the content from an array of strings into the file, and closes the file in one atomic operation.
  • WriteAllText – opens a file, writes the content into a string, and closes the file in one atomic operation.

Directory Class

Like the File class, the Directory class has a number of static methods to manipulate and create directories. These are the most important methods:

  • CreateDirectory – creates all directories in a supplied path.
  • Delete – deletes a specified directory.
  • Exists – determines whether a directory exists or not.
  • GetCreationTime – returns the time and date of creation of a directory.
  • GetCurrentDirectory – returns a DirectoryInfo object for the current working directory of the application.
  • GetDirectories – gets a list of names for subdirectories of a directory specified.
  • GetDirectoryRoot – returns the volume or root information for a specified directory.
  • GetFiles – returns the names of files in a directory.
  • GetFileSystemEntries – returns a list of files and subdirectories for a specified directory.
  • GetLastAccessTime – returns the time that a directory was last accessed.
  • GetLastWriteTime – returns the time that a specified directory was last written to.
  • GetLogicalDrives – creates a list of drives as strings in the format “C:\”.
  • GetParent – gets the parent directory of the specified directory.
  • Move – moves a file or directory to a specified place.
  • SetCreationTime – sets the time a specified directory was created.
  • SetCurrentDirectory – sets a specified directory to be the current working directory for the application.
  • SetLastAccessTime – sets the last time a directory was accessed.
  • SetLastWriteTime – sets the last time a directory was written to.

FileAccess Enumeration

The FileAccess enumeration provides members that are used to determine the access rights required when opening a file. These are:

  • Read
  • Write
  • ReadWrite

FileMode Enumeration

The FileMode Enumeration specifies how a file should be opened or created. These are:

  • Append – opens a file and moves the pointer in the FileStream object at the end. Can only be used with FileAccess.Write.
  • Create – creates a new file. If it exists it is overwritten.
  • CreateNew – creates a new file. If the file exists then it throws an exception.
  • Open – open an existing file. If the file does not exist, an exception is thrown.
  • OpenOrCreate – opens an existing file. If the file does not exist, it creates a new file.
  • Truncate – opens an existing file but empties the file so that it is zero bytes long.

FileStream Class

The FileStream class provides the functionality to open file streams for reading and writing. These are the most important methods:

  • CanRead – determines whether stream supports reading.
  • CanSeek – determines whether the stream supports seeking.
  • CanTimeout – determines whether the stream can time out.
  • CanWrite – determines whether the stream can write.
  • Handle – gets the stream’s underlying file handle.
  • Length – gets the length (bytes) of the stream.
  • Name – gets the name of the file.
  • Position – gets or sets the virtual cursor for determining where in the stream the current position is.
  • ReadTimeout – gets or sets the stream’s timeout for read operations.
  • WriteTimeout – gets or sets the stream’s timeout for write operations.
  • Close – closes the stream and releases any associated resources.
  • Flush – clears any buffers within the stream and forces any changes to be written to the underlying system or device.
  • Lock – prevents other processes from changing part of the file.
  • Read – performs a sequential read of a specified number of bytes and updates the position of the cursor accordingly.
  • ReadByte – performs a read of a single byte and updates the position of the cursor by one.
  • Seek – sets the position within the stream.
  • SetLength – specifies the length of the stream.
  • Unlock – lets other processes change the stream.
  • Write – writes sequentially a specified number of bytes and moves the cursor at the end.
  • WriteByte – writes one byte to the stream and moves the cursor one position.

StreamReader Class

The StreamReader class provides the functionality to read data from a Stream derived class. These are the important properties:

  • BaseStream – gets the underlying stream that the reader is reading.
  • CurrentEncoding – gets the current encoding used by the stream.
  • EndOfStream – determines whether the reader has encountered the end of the stream.

These are the most commonly used methods:

  • Close – closes the reader and the underlying stream.
  • Peek – returns the next character in the stream without moving the cursor.
  • Read – reads the next set of characters from the stream.
  • ReadBlock – reads the next block of characters from the stream.
  • ReadLine – reads the next line of characters in the stream.
  • ReadToEnd – reads all the characters through to the end of the stream.

How to Read a File in C#

Here is the code to open a file and read from it.

//first open the file
FileStream theFile = File.Open(@"C:\test.txt", FileMode.Open, FileAccess.Read);

//the File.Open returns a FileStream. We will create StreamReader that wraps the FileStream.
StreamReader reader = new StreamReader(theFile);

Console.WriteLine(reader.ReadToEnd());

//close reader and stream
reader.Close();
theFile.Close();

It is important to note that the StreamReader returns data as a string. The File class has additional methods that make it simpler to open a file for reading. The File class supports creating a StreamReader immediately without the need of wrapping a FileStream. This is done as follows.

StreamReader reader = File.Open(@"C:\test.txt");
Console.WriteLine(reader.ReadToEnd());
reader.Close();

If you want to read the whole file at one go then it can become even simpler as follows.

Console.WriteLine(File.ReadAllText(@"C:\test.txt"));

The last example shows code that is looking inside a file and finding a particular word (“test”).

StreamReader reader = File.Open(@"C:\test.txt");

while (!reader.EndOfStream)
{
    string line = reader.ReadLine();
    if (line.Contains("test"))
    {
        Console.WriteLine("Found test");
        break;
    }
}

StreamWriter Class

The StreamWriter class provides the functionality to write data to streams. The following are its important properties:

  • AutoFlush – gets or sets an indicator that shows whether every call to the Write method should flush changes to the underlying stream.
  • BaseStream – gets the underlying stream that the writer is writing.
  • Encoding – gets the encoding the underlying stream is using.
  • NewLine – gets or sets a string that contains the line terminator string. This is used only if you want to change the string that terminates every individual line.

The following are the most commonly used methods:

  • Close – closes the writer and the underlying stream.
  • Write – writes to the stream.
  • WriteLine – writes data to the stream followed by a string that terminates each individual line.

How to Write to a File in C#

The following is the code used to write to a file in C#.

StreamWriter writer = File.CreateText(@"C:\test.txt");
writer.WriteLine("Test");
writer.Close();

The StreamWriter can also write a chunk of text all at once.

File.WriteAllText(@"C:\test.txt", "Test1 Test2");

If you want to write to an existing file you use the follow code.

FileStream stream = File.OpenWrite(@"C:\test.txt");
StreamWriter writer = new StreamWriter(stream);
writer.Write("Hello World!");
writer.Close();
stream.Close();

Finally if you do not know whether a file exists or not but if it exists you want to append you use the following code.

FileStream stream = File.Open(@"C:\test.txt", FileMode.OpenCreate, FileAccess.Write);
StreamWriter writer = new StreamWriter(stream);
writer.Write("Hello World!");
writer.Close();
stream.Close();

Understanding Readers and Writers

The StreamReader and StreamWriter classes inherit from the TextReader and TextWriter abstract classes respectively. There are other readers and writers. These are:

  • StringReader/StringWriter – read to and write from in-memory strings.
  • BinaryReader/BinaryWriter – used to handle getting binary data to and from streams.

MemoryStream Class

This class provides the functionality to create in-memory streams. The following are the most important properties:

  • CanRead – determines whether the stream supports reading.
  • CanWrite – determines whether the stream supports writing.
  • CanSeek – determines whether the stream supports seeking.
  • CanTimeout – determines whether the stream can time out.
  • Capacity – gets or sets the number of bytes allocated for the stream.
  • Length – gets the length (in bytes) of the stream.
  • Position – gets or sets the position of the cursor in the stream.
  • ReadTimeout – gets or sets the time out for the read operation of the stream.
  • WriteTimeout – gets or sets the time out for the write operation of the stream.

These are the main MemoryStream methods:

  • Close – closes the stream and releases any resources associated with it.
  • Flush – clears any buffers within the stream and forces changes to be written to the underlying system or device.
  • GetBuffer – retrieves the array of unsigned bytes that was used to create the stream.
  • Read – performs a sequential read of a specified number of bytes and updates the position of the cursor.
  • ReadByte – reads a byte and moves the cursor position by one.
  • Seek – sets the position within the stream.
  • SetLength – specifies the length of the stream.
  • ToArray – writes the entire stream to an array of bytes.
  • Write – writes a number of specified bytes to the stream and updates the cursor accordingly.
  • WriteByte – writes a byte of data into the stream and moves the cursor one position.
  • WriteTo – writes the MemoryStream to another stream.

How to Use the Memory Stream

Here is an example how to use the MemoryStream and then write it to a FileStream.

MemoryStream memStream = new MemoryStream();
StreamWriter writer = new StreamWriter(memStream);
writer.WriteLine("Hello World");
//force the writer to push the data in the stream
writer.Flush();

FileStream theFile = File.Create(@"C:\test.txt");
memStream.WriteTo(theFile);
writer.Close();
theFile.Close();
memStream.Close();

The BufferedStream Class

The BufferedStream Class provides the basic functionality to wrap streams to improve performance by buffering reads and writes to the stream. Its most important properties and methods are the same as the MemoryStream.

How to use a BufferedStream

The BufferedStream should be used in situations when writing out data to a stream directly does not perform well. The following code demonstrates how to use a BufferedStream.

FileStream theFile = File.Create(@"C:\test.txt");
BufferedStream buffer = new BufferedStream(theFile);
StreamWriter writer = new StreamWriter(buffer);
writer.WriteLine("Hello");
writer.Close();

Well for today that is enough. In the next tutorial we will take a look at Compressed Streams. Until then bye bye!

Categories: C# .NET

C# .NET Tutorial 5: Navigating the File System

January 2, 2009 scerrimark 5 comments

Hello hope you are feeling fine and hope that you are looking forward for the new year. For those who are new this is number 5 of a series of C# tutorials. If you want to start from the beginning click on the C# category on the right and you will have all the tutorials in descending order. I recommend that you start from the first one and proceed from there. In the coming 4 tutorials ( 5 – 8 ) I will be talking about input and output in C# .NET. These include accessing files and folders on your system, reading and writing streams, compressing streams, and using isolated storage. In these four tutorials I am assuming that you can create a console application in Visual Studio (or Visual C# Express Edition), you can add references of class libraries to your project, and that you can create text files. So let’s start with the first tutorial.

The File System Classes

There are two sets of classes realted to the file system in the System.IO namespace. The first set is informational classes that all derive from the FileSystemInfo base class and are used to obtain information from the file system objects (files, directories, and drives). These classes are FileInfo, DirectoryInfo, and DriveInfo. The DriverInfo class does not inherit from the FileSystemInfo because it does not share the behaviour of files and directories. For example while you can delete files and folders, you cannot delete drives.

The utility classes, which include the File, Directory, and Path classes,  provide static methods to perform operations on files, directories, and file system paths.

FileSystemInfo Classes

The following are the properties of the FileSystemInfo class:

  • Attributes – gets or sets FileAttributes of the current file or directory.
  • CreationTime – gets or sets the time that the current file or directory was created.
  • Exists – checks whether a file or directory exist.
  • FullName – returns a full path for a file or directory.
  • LastAccessTime – gets or sets the time the file or directory was accessed.
  • LastWriteTime – gets or sets the time the file or directory was written to.
  • Name – returns the simple name.

The following are some of the commonly used methods in the FileSystemInfo class:

  • Delete – removes a file or directory from the system.
  • Refresh – updates the data in the class with the latest information from the file system.

FileInfo Class

This class provides the basic functionality to access and manipulate a single file in the system. The following are the most common properties:

  • Directory – returns the DirectoryInfo object that represents the directory in which this file is found.
  • DirectoryName – returns the name of the directory in which this file is found.
  • IsReadOnly – gets or sets the flag that determines whether a file can be modified or not.
  • Length – gets the length of the file.

The following are the important FileInfo methods:

  • AppendText – creates a new StreamWriter to append text to the file (will see in the next tutorial).
  • CopyTo – copies a file in a new location.
  • Create – creates a file.
  • CreateText – creates a new StreamWriter to create a text file.
  • Decrypt – decrypts a file that was encrypted by the current user.
  • Encrypt – encrypts a file so that only the current user can decrypt it.
  • MoveTo – moves a file to a new location.
  • Open – opens the file with specific privileges.
  • OpenRead – opens a file with read-only access.
  • OpenText – opens a file and returns a StreamReader to read from a text file.
  • OpenWrite – opens a file with write-only access.
  • Replace – replaces a file with the information in the current FileInfo object.

Get Information about a File

To get information about a file you need to:

  • Create a FileInfo object with the path of the file.
  • Accces the FileInfo object’s properties.

For example to check if a file exists you do the following:

FileInfo testFile = new FileInfo(@"c:test.dbf"); //the @ symbol is used so that the string is treated as is (raw).
if (testFile.Exists)
{
    Console.WriteLine("Filename: {0}", testFile.Name);
    Console.WriteLine("Path: {0}", testFile.FullName);
}

How to Copy a File

The FileInfo also let’s you do operations on the file. For example here we are making a copy of the file:

FileInfo testFile =  new FileInfo(@'c:test.dbf');
testFile.CopyTo(@"c:backuptest.dbf");

DirectoryInfo Class

This class provides the mechanism to access and manipulate a single directory on the file system. The following are the important properties of the DirectoryInfo class:

  • Parent – gets the DirectoryInfo for the parent directory of the current directory.
  • Root – gets the root part of the current directory as a string.

The following are the mostly used DirectoryInfo methods:

  • Create – creates a directory
  • CreateSubdirectory – creates a new directory as a child of the current directory
  • GetDirectories – returns an array of DirectoryInfo objects of the sub directories present in the current directory.
  • GetFiles – returns an array of FileInfo objects of all the files in the current directory.
  • GetFileSystemInfos – returns an array of FileSystemInfo objects that represents the files and directories in the current directory.
  • MoveTo – moves the current directory to a new location.

Enumerating Files in a Directory

To list the files in a directory you use the following code:

DirectoryInfo currentDir = new DirectoryInfo(@"C:backup");

foreach (FileInfo files in currentDir.GetFiles())
{
    Console.WriteLine("File: {0}", files.Name);
}

DriveInfo Class

To access and manipulate a single drive you use the DriveInfo class. Here are the commonly used properties:

  • AvailableFreeSpace – gets the amount of available space on the drive (can be different than TotalFreeSpace because of quotas).
  • DriveFormat – gets the format of the drive like NTFS, FAT32, etc.
  • DriveType – gets the type of drive in the form of DriveType enumeration.
  • IsReady – returns whether the drive can be accessed.
  • Name – returns the name of the drive.
  • RootDirectory – returns a DirectoryInfo object of the root directory of the drive.
  • TotalFreeSpace – gets the total amount of free space on the drive.
  • TotalSize – total size of the drive
  • VolumeLabel – gets or sets the label of the drive (set only if it is not readonly).

The most important method in the DriveInfo class is the GetDrives method which is a static method that returns all the drives on the system.

DriveType Enumeration

The DriveType enumeration provides the possible types of drives that can be stored in the DriverInfo class. These are:

  • CDRom – a cd or dvd drive.
  • Fixed – a fixed disk or hard drive disk.
  • Network – A network mapped drive.
  • NoRootDirectory – a drive without a root directory.
  • Ram – a RAM drive.
  • Removable – a drive that has removable media such as a USB drive.
  • Unknown

How To Enumerate Drives

To list all the drives you use the following code:

DriveInfo[] drives = DriveInfo.GetDrives();

foreach (DriveInfo drive in drives)
{
    Console.WriteLine("Drive: {0}", drive.Name);
    Console.WriteLine("Type: {0}", drive.DriveType);
}

Path Class

To manipulate a file system path you use the Path class. Here are some of its methods:

  • ChangeExtension – takes a path and returns a new path with the new extension (only the path string changes not the actual file extension).
  • Combine – combines two compatible path strings.
  • GetDirectoryName – returns the name of the directory in the specified path.
  • GetExtension – returns the name of the file extension in the specified path.
  • GetFileName – returns the name of the file in the specified path.
  • GetFileNameWithoutExtension – returns the name of the file without extension in the specified path.
  • GetFullPath – returns a full path of the specified path.
  • GetPathRoot – returns the root directory name in the specified path.
  • GetRandomFileName – generates a random file name.
  • GetTempFileName – generates a temporary file in the file system and returns it’s path.
  • GetTempPath – returns the path for the temporary file directory for the current user or system.
  • HasExtension – indicates whether a specified file path has an extension.
  • IsPathRooted – indicates whether a specified path includes a root directory.

How to Change a File Extension

Here is the code to change a file extension:

string path = @"C:test.dbf";

Console.WriteLine("Extension: {0}", Path.GetExtension(path));
Console.WriteLine("New Extension {0}", Path.ChangeExtension(path, "bak"));

FileSystemWatcher Class

The FileSystemWatcher class is used to monitor file system directories for changes. Here are some of it’s properties:

  • EnableRaisingEvents – gets or sets whether the watcher object should raise events. It is used to turn on or off the watching of a directory.
  • Filter – gets or sets the filter that determines which files to watch.
  • IncludeSubdirectories – gets or sets an indicator of whether the watching of a directory includes also the sub directory.
  • NotifyFilter – gets or sets the type of changes to watch for. By default all are watched for.
  • Path – gets or sets the path to the directory to monitor.

The most important method in the FileSystemWatcher class is the WaitForChanged method. This is a synchronous method for watching a directory for changes and for returning a structure that contains all the changes.

The following are the events related to the FileWatcherSystem class. The events are self-explanatory:

  • Changed
  • Created
  • Deleted
  • Renamed

How to Monitor Changes in a Directory

To monitor changes in a directory the following procedure needs to be used:

  • Create a new FileSystemWatcher object specifying the directory in the Path property.
  • Register for the events.
  • Turn on the events by setting EnableRaisingEvents to true.

The following code demonstrates this procedure:

FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = @"c:";

//Register for events
watcher.Created += new FileSystemEventHandler(watcherChanged);
watcher.Deleted += new FileSystemEventHandler(watcherChanged);

//turn on events
watcher.EnableRaisingEvents = true;

//Event handler
static void watcherChanged(object sender, FileSystemEventArgs e)
{
    Console.WriteLine("Directory Changed");
}

When watching the file system you can get more changes than the FileSystemWatcher can handle. In such case the FileSystemWatcher will throw an Error event.

Well that’s the end for today’s tutorial. It was quite interesting right? Leave your comments and I will see you for the next tutorial on I/O – reading and writing files.

Categories: C# .NET Tags: