You are on page 1of 14

Stream Classes

The .NET Framework classes offer a streams-based I/O framework, with the core classes in the System.IO namespace. All classes that represent streams inherit from the Stream class, and the key classes are listed in Table 1. Table 1 - String and WriteLine Format Specifiers Class Stream Description The abstract base class Stream supports reading and writing bytes. In addition to basic Stream behavior, this class supports random access to files through its Seek method and supports both FileStream synchronous and asynchronous operation. A nonbuffered stream whose encapsulated data is directly accessible in memory. This stream has no backing store and might be useful as MemoryStream a temporary buffer. A Stream that adds buffering to another Stream, such as a NetworkStream. (FileStream already has buffering internally, and a MemoryStream doesn't need buffering.) A BufferedStream object can be composed around some types of streams to improve read and BufferedStream write performance. The abstract base class for StreamReader and StringReader objects. While the implementations of the abstract Stream class are designed for byte input and output, the implementations of TextReader are TextReader designed for Unicode character output. Reads characters from a Stream, using Encoding to convert StreamReader characters to and from bytes. Reads characters from a String. StringReader allows you to treat a String with the same API; thus, your output can be either a Stream in StringReader any encoding or a String. The abstract base class for StreamWriter and StringWriter objects. While the implementations of the abstract Stream class are designed for byte input and output, the implementations of TextWriter are TextWriter designed for Unicode character input. Writes characters to a Stream, using Encoding to convert characters StreamWriter StringWriter to bytes. Writes characters to a String. StringWriter allows you to treat a String with the same API; thus, your output can be either a Stream in any

encoding or a String. BinaryReader BinaryWriter Reads binary data from a stream. Writes binary data to a stream.

Two classes derived from Stream but not listed in Table 1 are offered in other namespaces. The NetworkStream class represents a Stream over a network connection and resides in the System.Net.Sockets namespace, and the CryptoStream class links data streams to cryptographic transformations and resides in the System.Security.Cryptography namespace. The design of the Stream class and its derivatives is intended to provide a generic view of data sources and destinations so that the developer can interchangeably use any of these classes without redesigning the application. In general, Stream objects are capable of one or more of the following:

Reading The transfer of data from a stream into a data structure, such as an array of bytes Writing The transfer of data from a data structure into a stream Seeking The querying and modifying of the current position within a stream

Note that a given stream might not support all these features. For example, NetworkStream objects don't support seeking. You can use the CanRead, CanWrite, and CanSeek properties of Stream and its derived classes to determine precisely which operations a given stream does in fact support.

Beginners to the .NET Framework sometimes have a hard time trying to understand the classes in the System.IO namespace for performing input/output (IO) operations. The difficulty stems from the fact that this namespace is relatively large, containing more than 40 members, some of which are similar classes that can be used to achieve the same tasks. Thus it is sometimes hard to figure out which class is best for which task. This article tries to make your life a bit easier by grouping IO tasks into three categories and introducing the classes that are suitable for each task category. Input/output (IO) refers to the operations for reading and writing data to streams and files. In the .NET Framework, you use the classes in the System.IO namespace to perform these operations. This article starts with the basic classes such as theFile and FileInfo classes -- classes used to perform file operations such as creating, copying, and deleting files. Other basic classes include Directory andDirectoryInfo, which provide functionality to manipulate directories, and Path, which supports application portability. In addition to those classes, there are also classes you can use to read and write the contents of a file. The System.IO namespace provides a number of classes that allow you to do basically similar things. These classes can be roughly grouped into three categories:

Classes for reading and writing bytes. Classes for reading and writing characters. Classes for reading and writing binary data.

In the first group are stream classes that are derived from the Stream class. In the second category are reader and writer classes, such asStreamReader and StreamBuffer. The third group includes classes such as BinaryReader andBinaryWriter. Which class you should use for your input and output operations will depend on the kind of data you are going to work with.

The File Class


You use the File class to manipulate a file; to create, copy, or delete it, and check if it exists. You also use it to open a file for reading and writing. To read from and write to a file itself, however, you need to use other classes, such as the FileStream or the BufferedStream class. TheFile class constructor is private, so you cannot instantiate a file using the new keyword. This is not necessary because all methods of the Fileclass are static. These static methods perform security checks every time they are called. This, of course, has performance consequences, and sometimes is not needed. If you need to access the same file frequently, use the FileInfo class instead. The following is the list of the most important methods of the File class:

Create
Creates a file in a specified directory. You call this method passing a file path or a file path and an integer of a buffer size for the resulting FileStream object. For example, the following code creates a file called newFile.txt in the C:\data directory, returns a FileStream, and then closes the FileStream object straight away:

FileStream fs = File.Create("C:/data/newFile.txt"); fs.Close();

For more information on the FileStream class, see the section "The FileStreamClass" later in this article. As another example, the following code creates aFileStream with a buffer size of 16KB.

FileStream fs = File.Create(" C:/123data/newFile.txt", 16384);

If the file c:\data\newfile.txt already exists, it will be overwritten.

CreateText
Creates a file and returns a StreamWriter object that you can use to write text into that file. Like Create, you pass a file path to the method, and any existing file will be overwritten. For example:

StreamWriter sw = File.CreateText(" C:/123data/new.txt");

See the "The StreamWriter Class" section later in this article for more details onStreamWriter.

AppendText

Returns a StreamWriter object to a specified existing file. The text you write will then be appended to the end of the file. If the file does not exist, AppendText will create a new file. You pass a file path to this method.

Exists
Returns true if a file in a specified path exists; otherwise, it returns false. Its only parameter is a path and filename.

Copy
Copies a file to another folder. There are two overloads of this method, as follows:

public static void Copy( string sourceFileName, string destFileName ); public static void Copy( string sourceFileName, string destFileName, bool overwrite );

The first overload of the method will throw an IOException if the destination file already exists. So will the second overload, if the overwrite argument is false. For both overloads, a FileNotFoundException will be thrown if the source file does not exist. In addition, the method can throw an ArgumentException if eithersourceFilename or destinationFilename is invalid.

Move
Moves a file to another directory. The Move method has the same syntax as the first overload of the Copy method. The difference from the Copy method is that Movedeletes the source file.

Open
Opens a file and returns a FileStream object. If the file to be opened does not exist, a FileNotFoundException exception is thrown. This method has three overloads, all of which require that you pass a path and filename as the first argument and a member of the FileMode enumeration as the second. The second and third overloads require a member of the FileAccess enumeration as their third argument, while the third overload requires a member of the FileShare enumeration as its fourth argument. The FileMode enumeration tells the operating system how the file should be opened. Its members are Append, Create, CreateNew, Open, OpenOrCreate, andTruncate. The FileAccess enumeration indicates to the operating system whether the

file is to be opened for reading or writing. Its members are Read,ReadWrite, and Write. The FileShare enumeration tells the operating system how to control access to the same opened file from other threads, processes, or users. Its members areInheritable, None, Read, ReadWrite, and Write. If the value of the argument is FileShare.Write, for example, other programs can write to the opened file.

OpenRead
Opens a file as read-only and returns aFileStream object. Its only parameter is the path and name of the file. This is a single-purpose version of the Open method.

OpenText
Opens a file and returns a StreamReader object. Its only parameter is the path and name of the file.

OpenWrite
Opens a file and returns a Stream object. You can use this Stream object to read and write to the file. The method's only parameter is the path and name of the file.

GetAttributes
Obtains the file's attributes, as expressed in a bitwise combination of the members of the FileAttributes enumeration: Archive, Compressed, Device, Directory,Encrypted, Hid den, Normal, NotContentIndexed, Offline, ReadOnly, ReparsePoint,SparseFile, System, and Temporary.

SetAttributes
Changes the attribute of a file. You pass a file path and a bitwise combination of the members of the FileAttribute enumeration to this method.

The

FileInfo

Class

The File class has static methods that can be conveniently used without having to have an instance of a File object; however, those methods always perform security checks that adversely affect performance. The FileInfo class provides similar methods for similar tasks, but without security checks. You should use FileInfo if you are going to access a file several times. Also, unlike File, methods in FileInfoare instance methods. To create a FileInfo object, pass a valid file path to its constructor. The Create method, for example, behaves like the Create method of theFile class. For instance, the following code uses the FileInfo class to create a file:

FileInfo fileInfo = new FileInfo("C:/NextGen.txt"); FileStream fs = fileInfo.Create();

The

Directory

Class

The Directory class represents a directory. Its constructor is private, so you cannot use the new keyword to construct a Directory object. That is not necessary, in any case, because all methods of the Directory class are static. The Directory class performs security checks on all of

its methods, resulting in slightly reduced performance. If you will be accessing the same directory often, use theDirectoryInfo class instead; it is described in the section "The DirectoryInfoClass." The following are some of the important methods of the Directory class:

CreateDirectory
Creates a directory in the specified path. If the directory's parent does not exist, the parent directory will also be created. For example, if you pass the pathC:\data\projects\RD to this method and the projects directory does not exist, both the RD and projects directories will be created. The return value of this method is aDirectoryInfo object representing the created directory. For example:

DirectoryInfo dirInfo = Directory.CreateDirectory(" C:/data/Projects/RD"); System.Console.WriteLine(dirInfo.Name); // prints "RD"

For more information about DirectoryInfo, see the "The DirectoryInfo Class" section.

Delete
Deletes an existing directory and, optionally, all of its subdirectories and files. If the directory does not exist, a DirectoryNotFoundException will be thrown. This method has two overloads, as follows:

public static void Delete(string path); public static void Delete(string path, bool recursive);

The first overload allows you to pass an empty directory to delete. If the directory is not empty, an IOException will be thrown. The second overload enables you to delete a directory and all of its subdirectories and files, if the recursive argument is set to true.

Exists
Returns true if the specified directory exists; otherwise, it returns false. Its single argument is the path to the directory.

GetDirectories

Returns an array of strings containing all of the subdirectories of a directory. The first overload is the most straightforward; it accepts a valid path to the directory, the subdirectories of which you want to obtain. The second overload allows you to specify a pattern as the second argument. For example, with the second overload, you can obtain only subdirectories that have names beginning with a certain substring, as illustrated by the following code, which prints all of the subdirectories of the C:\ drive that start with the letter W or w:

string[] dirs = Directory.GetDirectories("C:\\", "W*"); int count = dirs.Length; for (int i=0; i<count; i++) System.Console.WriteLine(dirs[i]);

GetFiles
Returns all of the files in a directory. Like the GetDirectories method, this method has two overloads. The first overload returns an array of Strings containing the filenames in a directory. The second overload allows you to specify a pattern as the second argument. For example, the following code prints all of the files in the C:\drive that start with the letter A or a:

string[] files = Directory.GetFiles("C:\\", "A*"); int count = files.Length; for (int i=0; i<count; i++) System.Console.WriteLine(files[i]);

GetLogicalDrives
Returns an array of Strings containing all of the logical drive names of the current computer in the format <drive_letter>:\. For example, the following code prints all of the drive names in the computer:

string[] drives = Directory.GetLogicalDrives(); int count = drives.Length; for (int i=0; i<count; i++) System.Console.WriteLine(drives[i]);

GetParent
Returns a DirectoryInfo object representing the parent directory of the specified directory. Its single argument is the path of the directory, the parent of which is to be returned.

Move
Moves a specified directory and all of its subdirectories and files to a new location. This method accepts two arguments: the path of the source directory, and the path to the new location.

GetCurrentDirectory

Returns a String object containing the full path to the current directory. Ths method has no parameters.

SetCurrentDirectory
Sets a new current directory. This method's only argument is the path of the directory to make current.

The

DirectoryInfo

Class

The Directory class provides a convenient way of manipulating directories. The convenience comes at a price, however: the Directory class performs security checks on all of its methods. If you are going to access the same directory multiple times, you can avoid these security checks by using the DirectoryInfo class, which provides methods similar to those in the Directory class, but with all of its methods instance methods. Therefore, you must first construct a DirectoryInfo object by passing a path to its constructor, as in the following code:

DirectoryInfo dirInfo = new DirectoryInfo("C:/data");

Constructing a DirectoryInfo object does not mean creating a directory if it does not yet exist. To create a directory, you need to call the Create method, as shown in the following code:

DirectoryInfo dirInfo = new DirectoryInfo(" C:/XFiles.txt"); dirInfo.Create();

If the directory already exists, the call to the Create method does not throw an exception. If, after constructing a DirectoryInfo object representing a non-existent directory, however, you call other methods that require that the directory exist, aDirectoryNotFoundException will be thrown. For example, the Delete,GetDirectories, GetFile, and MoveTo methods require the DirectoryInfo object to represent a directory that exists.

The

Path

Class

The Path class provides properties and methods that you can use to write portable applications, when your applications need to run on more than one operating system. As you may be aware, different operating systems have different directory and file naming conventions. For example, the Windows operating system recognizes the back-slash (\) character as a directory separator. In Unix or Linux, however, the forward slash (/) character is used to separate a directory from a subdirectory. By using the Path class, you can write applications that will run on multiple operating systems without changing your code. For example, the static fieldDirectorySeparatorChar translates into the directory separator character of the operating system on which the application is run. Therefore, if you need to access a file called flower.gif in a subdirectory named images, you can specify the following string as a relative path to the file:

string path = "images" + Path.DirectorySeparatorChar + "Flower.gif";

The following list give the other static fields.

PathSeparator
Returns a character that is used to separate paths in the current operating system. For Windows, this is the semicolon (;) character.

AltDirectorySeparatorChar
Returns a character which is the alternate directory separator character for the current operating system. In Unix or Linux, this character is the back slash (\). In Windows and Macintosh, this character is the forward slash (/).

InvalidPathChars
Returns an array of characters that cannot be used in a path in the current operating system. For instance, in Windows, you cannot have a filename that contains an asterisk or a question mark. You can use this field to verify the validity of a filename entered by the user.

The

Stream

Class

The Stream class is an abstract class that is implemented by BufferedStream,FileStream, MemoryStream, NetworkStream, and CryptoStream. The two child classes that are frequently used and will be discussed in this section are FileStream andBufferedStream. Even though you cannot instantiate a Stream object directly, sometimes you obtain aStream object from a method, such as the OpenFile method of theSystem.Windows.Forms.OpenFileDialog class. To improve performance, you might want to wrap the Stream object inside of a BufferedStream object. For more information about the BufferedStream class, see the section "The BufferedStreamClass." The Stream class provides functionality that enables programmers to manipulate aStream. For example, the Length property returns the number of bytes in the Streamobject, and the Position property specifies the position of the pointer in the stream. Three other properties are CanRead, CanWrite, and CanSeek, all of which are self-explanatory. Among others, the Stream class provides methods for reading and writing. When a read or write operation is performed, the position of the Stream is advanced by the number of bytes read or written. The following are some are some of the more important methods of the Stream class.

Close

Closes the Stream object and frees all of the resources it consumes. Even though unused resources will eventually be garbage collected, it is good programming practice to always call this method when you no longer need a Stream object.

Flush
Forces the contents of the buffer to be written to the underlying device. For example, in a FileStream, this method writes the buffer to the file.

Read
Reads available data to an array of bytes. This method returns an Integer that indicates the number of bytes read. If the pointer is at the end of the stream whenRead is called, the method will return zero. The method has the following signature:

public abstract int Read( in byte[] buffer, int offset, int count )

The bytes read will be placed in the buffer. You can specify the maximum number of bytes that can be read in count. If count is greater than the number of available bytes, only the available bytes will be returned. The offset argument specifies the number of bytes that need to be skipped before starting to read. If you specify 0 for offset, the read operation will start from the byte pointed to by the stream pointer.

ReadByte
This method reads one byte and casts it into an integer, which is returned by the method. If the end of the stream has been reached when this method is called, a -1 is returned. The method has no parameters.

Write
This method writes an array of bytes into the stream. It does not return any value, and has the following signature:

public abstract void Write( byte[] buffer, int offset, int count )

The Write method writes the buffer byte array into the stream. It will write the number of bytes specified by count and skip the offset number of bytes in buffer before starting the write operation. Note that count must not be greater than the number of available bytes in the buffer.

WriteByte

Writes a single byte to the stream. This method accepts a byte as its argument and does not return a value.

The

FileStream

Class

The FileStream class represents a stream that wraps a file. You use FileStream for reading and writing bytes of a file. The FileStream class uses buffering to improve performance. The easiest way to construct a FileStream object is to use one of its constructors, which accepts a file path and a value from the FileMode enumeration as arguments. For instance, the following code creates a file called newFile.txt and writes two bytes into it. If the file already exists, the file will be overwritten:

FileStream fs = new FileStream("C:/newFile.txt", FileMode.Create); Byte[] bytes = new Byte[2]; bytes[0] = 65; bytes[1] = 66; fs.Write(bytes, 0, 2); fs.Close();

Some methods return a FileStream object without requiring that you create it with one of its constructors. For example, the following code uses the File class' Createmethod to create a file called newFile.txt, returns a FileStream object, and then writes two bytes to the file:

FileStream fs = File.Create("C:/newFile2.txt"); Byte[] bytes = new Byte[2]; bytes[0] = 65; bytes[1] = 66; fs.Write(bytes, 0, 2); fs.Close();

If you want to append to a file instead of creating a new one, you must use theFileStream constructor that accepts a FileMode and a FileAccess value, and you must specify FileAccess. Write for the file access type, as shown in the following code:

FileStream fs = new FileStream("C:/newFile.txt", FileMode.Append, FileAccess.Write);

To read from a file, you can use FileMode. Open as the file mode argument in one of the FileStream class' constructors. The following code, for instance, reads two bytes from the newFile.txt file:

FileStream fs = new FileStream("C:/newFile.txt", FileMode.Open); Byte[] bytes = new Byte[2]; int i = fs.Read(bytes, 0, 2); fs.Close ();

The

BufferedStream

Class

The BufferedStream class is used to wrap a Stream object and supports buffering to improve performance. There are two constructors that you can use to create aBufferedStream object. The first one accepts a Stream object. The BufferedStreamobject constructed using this constructor has a buffer size of 4,096 bytes. The second constructor accepts a Stream object as well as an Integer specifying the size of the buffer, allowing you to set your own buffer size. As an example of how to use the BufferedStream, consider the following code, which wraps the Stream object returned from an OpenFileDialog in a BufferedStreamobject and reads the first 128 bytes of the selected file:

OpenFileDialog openFileDialog = new OpenFileDialog(); if (openFileDialog.ShowDialog() == DialogResult.OK) { string filepath = openFileDialog.FileName; // Open the file using the OpenFile method BufferedStream bufferedStream = new BufferedStream( openFileDialog.OpenFile()); Byte[] bytes = new Byte[128]; bufferedStream.Read(bytes, 0, 128); }

Note that the BufferedStream class is derived from the Stream class; therefore, it inherits all of the Stream class' methods and properties.

The

StreamReader

Class

The StreamReader class is a child class of TextReader. You use StreamReader and other Reader classes to manipulate text. With this class, you can use the Readmethod to read one character each time or a fixed number of characters, or you can use the ReadLine method to read a line of text. You can construct a StreamReaderobject from a Stream object returned by a method call, or by specifying a path to a file to one of the StreamReader class constructors. Optionally, you can also pass an encoding scheme to a constructor to tell theStreamReader object the encoding used in the text file. If no encoding is supplied, the default encoding (System.Text.UTF8Encoding) is assumed. The stream's current encoding can be retrieved from the read-only CurrentEncoding property. As an example, the following code opens a text file named CompanySecret.txt and uses the ReadLine method to print the text to the Debug window one line at a time. The ReadLine method returns a null reference if it encounters the end of the stream:

StreamReader sr = new StreamReader(" C:/CompanySecret.txt"); string line = sr.ReadLine(); while (line != null) { System.Console.WriteLine(line);

line = sr.ReadLine(); } sr.Close();

Note that when you read a line of text using the ReadLine method, the end-of-line character is not included in the returned String.

The

StreamWriter

Class

The StreamWriter class is derived from the TextWriter class and can be used to write text to a stream. You can create an instance of the StreamWriter class by assigning it a Stream object returned by a method call, or by passing a file path to one of its constructors. Like the StreamReader class, you can also pass an encoding scheme of your choice to one of its constructors. The most important methods of theStreamWriter class are Write and WriteLine. Write enables you to write a character, an array of characters, or a string. The WriteLine method accepts a String and adds an end-of-line character to the end of the string. For example, the following code opens a new file called NewCompanySecret.txt and writes a string of text to it:

StreamWriter sw = new StreamWriter(" C:/NewCompanySecret.txt"); string line = "Don't tell anyone!!!"; sw.WriteLine(line); sw.Close();

The

BinaryReader

Class

You use the BinaryReader class to read binary data from a file. You can construct aBinaryReader object by passing its constructor a Stream object; you can't pass a file path to create a BinaryReader object. Once you have a BinaryReader object, you can use one of its ReadXXX methods to read various types of data. For example, theReadByte method is used to read a byte, and the ReadString method is used to read a String. The data must be read in the order it was written. For example, if you store a byte and then a string to a binary file, you must first read a byte and then read a String. The BinaryReader class also has a Read method, which has three overloads that allow you to read a character, an array of bytes, or an array of characters. As an example, here is the code that reads a byte and a string from a binary file called MyBinary.bin:

BinaryReader br = new BinaryReader(File.OpenRead(" C:/MyBinary.bin")); Byte b2 = br.ReadByte(); string s2 = br.ReadString(); System.Console.WriteLine(s2); System.Console.WriteLine(b2); br.Close();

The

BinaryWriter

Class

The BinaryWriter class is used to write binary data to a stream. You can construct aBinaryWriter object by passing a Stream object; you cant pass a file path to create a BinaryWriter object. In addition, there is also a parameterless constructor. The BinaryWriter class most important method is Write. This method has 18 overloads that guarantee that you can write any type of data to a BinaryWriter object. For example, the following code creates a BinaryWriter object that is linked to a new file called MyBinary.bin, and writes a byte and a string:

BinaryWriter bw = new BinaryWriter(File.Create(" C:/MyBinary.bin")); Byte b = 17; string s = "August"; bw.Write(b); bw.Write(s); bw.Close();

You might also like