only for RuBoard - do not distribute or recompile |
The FCL provides a streams-based I/O framework that can handle a wide range of stream and backing store types. This support for streams also infuses the rest of the FCL, with the pattern repeating in non-I/O areas such as cryptography, HTTP support, and more.
This section describes the core stream types and provides examples. The types mentioned in this section all exist in the System.IO namespace.
A stream represents the flow of data coming in and out of a backing store. A backing store represents the endpoint of a stream. Although a backing store is often a file or network connection, in reality it can represent any medium capable of reading or writing raw data.
A simple example would be to use a stream to read and write to a file on disk. However, streams and backing stores are not limited to disk and network I/O. A more sophisticated example would be to use the cryptography support in the FCL to encrypt or decrypt a stream of bytes as they move around in memory.
Stream is an abstract class that defines operations for reading and writing a stream of raw, typeless data as bytes. Once a stream has been opened, it stays open and can be read from or written to until the stream is flushed and closed. Flushing a stream updates the writes made to the stream; closing a stream first flushes the stream, then closes the stream.
Stream has the properties CanRead, CanWrite, Length, CanSeek, and Position. CanSeek is true if the stream supports random access and false if it only supports sequential access. If a stream supports random access, set the Position property to move to a linear position on that stream.
The Stream class provides synchronous and asynchronous read and write operations. By default, an asynchronous method calls the stream's corresponding synchronous method by wrapping the synchronous method in a delegate type and starting a new thread. Similarly, by default, a synchronous method calls the stream's corresponding asynchronous method and waits until the thread has completed its operation. Classes that derive from Stream must override either the synchronous or asynchronous methods but may override both sets of methods if the need arises.
The FCL includes a number of different concrete implementations of the abstract base class Stream. Each implementation represents a different storage medium and allows a raw stream of bytes to be read from and written to the backing store.
Examples of this include the FileStream class (which reads and writes bytes to and from a file) and the System.Net.Sockets.NetworkStream class (which sends and receives bytes over the network).
In addition, a stream may act as the frontend to another stream, performing additional processing on the underlying stream as needed. Examples of this include stream encryption/decryption and stream buffering.
Here is an example that creates a text file on disk and uses the abstract Stream type to write data to it:
using System.IO; class Test { static void Main( ) { Stream s = new FileStream("foo.txt", FileMode.Create); s.WriteByte(67); s.WriteByte(35); s.Close( ); } }
The Stream class defines operations for reading and writing raw, typeless data in the form of bytes. Typically, however, you need to work with a stream of characters, not a stream of bytes. To solve this problem, the FCL provides the abstract base classes TextReader and TextWriter, which define a contract to read and write a stream of characters, as well as a set of concrete implementations.
TextReader and TextWriter are abstract base classes that define operations for reading and writing a stream of characters. The most fundamental operations of the TextReader and TextWriter classes are the methods that read and write a single character to or from a stream.
The TextReader class provides default implementations for methods that read in an array of characters or a string representing a line of characters. The TextWriter class provides default implementations for methods that write an array of characters, as well as methods that convert common types (optionally with formatting options) to a sequence of characters.
The FCL includes a number of different concrete implementations of the abstract base classes TextReader and TextWriter. Some of the most prominent include StreamReader and StreamWriter, and StringReader and StringWriter.
StreamReader and StreamWriter are concrete classes that derive from TextReader and TextWriter, respectively, and operate on a Stream (passed as a constructor parameter).
These classes allow you to combine a Stream (which can have a backing store but only knows about raw data) with a TextReader/TextWriter (which knows about character data, but doesn't have a backing store).
In addition, StreamReader and StreamWriter can perform special translations between characters and raw bytes. Such translations include translating Unicode characters to ANSI characters to either big- or little-endian format.
Here is an example that uses a StreamWriter wrapped around a FileStream class to write to a file:
using System.Text; using System.IO; class Test { static void Main( ) { Stream fs = new FileStream ("foo.txt", FileMode.Create); StreamWriter sw = new StreamWriter(fs, Encoding.ASCII); sw.Write("Hello!"); sw.Close( ); } }
StringReader and StringWriter are concrete classes that derive from TextReader and TextWriter, respectively, and operate on a string (passed as a constructor parameter).
The StringReader class can be thought of as the simplest possible read-only backing store because it simply performs read operations on that string. The StringWriter class can be thought of as the simplest possible write-only backing store because it simply performs write operations on that StringBuilder.
Here is an example that uses a StringWriter wrapped around an underlying StringBuilder backing store to write to a string:
using System; using System.IO; using System.Text; class Test { static void Main( ) { StringBuilder sb = new StringBuilder( ); StringWriter sw = new StringWriter(sb); WriteHello(sw); Console.WriteLine(sb); } static void WriteHello(TextWriter tw) { tw.Write("Hello, String I/O!"); } }
The File and Directory classes encapsulate the operations typically associated with file I/O, such as copying, moving, deleting, renaming, and enumerating files and directories.
The actual manipulation of the contents of a file is done with a FileStream. The File class has methods that return a FileStream, though you may directly instantiate a FileStream.
In this example, you read in and print out the first line of a text file specified on the command line:
using System; using System.IO; class Test { static void Main(string[] args) { Stream s = File.OpenRead(args[0]); StreamReader sr = new StreamReader(s); Console.WriteLine(sr.ReadLine( )); sr.Close( ); } }
only for RuBoard - do not distribute or recompile |