C#'s core I/O classes and interfaces are defined in the System.IO namespace. The System.IO.Stream class is an abstract class that abstracts out the concept of a stream as merely a sequence of bytes. A stream can be read from or written to synchronously or asynchronously depending on the method call you use. A stream of bytes is usually associated with the underlying medium on which I/O operations such as a read/write are carried out. The medium can be an I/O device, a disk file, memory, or a TCP/IP socket. Java has a similar concept of streams (java.io.InputStream and java.io.OutputStream). The C# System.IO.Stream class is somewhat equivalent to the Java classes, although it does not have separate classes for reading and writing; instead, it has CanRead and CanWrite properties that indicate which operation can be carried out on the stream.
There are certain basic operations that can be carried out on all subclasses of the System.IO.Stream class. Table 15.1 shows a subset of these operations that are obvious to Java programmers.
Class | Description |
---|---|
Read | Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read.
[Serializable] public abstract int Read( in byte[] buffer, int offset, int count ); |
Write | Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. |
Close | Closes the current stream and releases any system resources associated with the stream. |
Flush | Writes the underlying stream's buffered data to be written to the underlying device the stream is abstracting. |
Seek | Sets the position within the current stream. |
Java Class | Java Method | Equivalent C# System.IO.Stream Method |
---|---|---|
java.io.InputStream | read() | Read() |
java.io.OutputStream | write() | Write() |
java.io.InputStream | close() | Close() |
java.io.OutputStream | close() | Close() |
java.io.OutputStream | flush() | Flush() |
java.io.InputStream | mark, markSupported(), reset() | Seek() |
Note that the System.IO.Stream class has both the Read() and Write() methods because it can function as both an input stream and an output stream.
Table 15.2 shows the equivalency between Java's I/O class methods and C#'s System.IO.Stream methods.
The C# Stream class has the Length and Position properties, which make it easy to determine your progress in accessing (reading or writing) the stream. In Java, the onus of keeping track of the position inside the stream is on the programmer.
You can use the CanSeek, CanRead, and CanWrite properties to decide whether you are dealing with an input or an output operation. Listing 15.1 shows the Stream class in action.
using System; using System.IO; public class Test { public static void Main(string[] args) { Stream s = null; try { s = new MemoryStream(); WriteStream(s); ReadStream(s); BulkWriteStream(s); BulkReadStream(s); SeekStream(s); } finally { s.Close(); } } private static void WriteStream(Stream s) { for (int i = 0; i < 100; ++i) s.WriteByte((byte)i); } private static void ReadStream(Stream s) { s.Position = 0; int i = 0; while ((i = s.ReadByte()) != 1) { Console.WriteLine(i); } } private static void BulkReadStream(Stream s) { s.Position = 0; byte[] arr = new byte[s.Length]; int bytesRead = 0; int bytes2Read = (int) s.Length; while (bytesRead > 0) { int val = s.Read(arr,bytesRead, bytes2Read); if (val == 0) break; bytes2Read = val; bytesRead += val; } } private static void BulkWriteStream(Stream s) { byte[] bytes = new byte[100]; s.Write(bytes,0, 100); s.Flush(); } private static void SeekStream(Stream s) { long start = 1; while (s.Position != 1){ long position = s.Seek(start, SeekOrigin.End); Console.WriteLine(s.ReadByte()); ——start; } } } |
In ReadStream() and WriteStream() we read and write one byte at a time. In BulkReadStream and BulkWriteStream we read and write as much as we can using byte[].
Note how the Position property is used to determine the position in the stream. After the first method call (WriteStream), the position is 100. This must be reset to 0 so that ReadStream() can read the stream from the beginning. Note that in BulkReadStream the Read(byte[], int, int) method may not read all the bytes at once, and hence we must keep track of how many bytes are read and how many are to be read.
In the last method call, SeekStream(), we try to go backwards in the Stream. We use C#'s Seek() method call to initially position the stream pointer at the end of the Stream. We use the SeekOrigin enumeration to specify where we want to position the pointer. After the pointer is positioned, we read one byte at a time. Here, the ReadByte() method moves one byte in the opposite direction until we reach the beginning of the Stream.
The four subclasses of the Stream class are FileStream, Buffered Stream, MemoryStream, and NetworkStream. Let's look at each subclass in turn.
18.188.70.255