Streams are sequence of bytes that you can use to read from or write to a backing store.
Let’s break down last sentence into a few parts:
- „Stream is a sequence of bytes“ – When working with data it is preferable that we read data in chunks of bytes. By breaking data in chunks we do not have to wait for our application to retrieve all parts of a data. For example, we may be accessing a audio file from network location and we want to process that audio file. Retrieving that file would take time and our application would need to wait until retrieval process is done before it can do some job. When using Streams we can specify how large chunks will be. You have seen this example: when listening to a music from popular music streaming site you will see information about bit-rate, that bit-rate represents chunk of data that is downloaded to you device for consumption.
- „that you can use to read from or write“ – Stream allows us to read, write or both to a storage device.
- „to a backing store“ – backing store represents your local Hard drive, memory, network location or any type of storage medium.
System class in System.IO namespace is a base class for all streams.
When using streams type of file (.txt, .mp3, .mkv, .doc, …) does not matter because it will be transformed to a sequence of bytes and your job is to convert that sequence to a meaningful representation of data. Retrieving data from a backing store will store data in a memory so you can use it in your application.
Every backing store type has appropriate streaming class for reading and writing operations. These streams are called Base Streams retrieve bytes. To consume:
- FileSytem (local Hard drive, usbv drive…) you would use FileStream
- Local memory -> MemoryStream
- Remote location (Internet, Local network) -> NetworkStream
You use Stream Adapters allow you to transform bytes to types you would usually use in your application, such as integers and strings, by giving you access to classes and methods to consume data. Most commonly used are:
- StreamReader/StreamWriter
- BinaryReader/BinaryWriter
- XmlReader/XmlWriter
For Streams to know where is beginning, current position, and end of a stream, pointer is used. Default position of pointer is at the beginning of a stream, or poistion 0. Streaming ends when pointer hits last position in a stream.
Example:
Lets say that we need to read 10 bytes which will be redistributed to positions 0-9, and we read data in chunks of 4 bytes. First we will read first 4 bytes and pointer will be at the position 3, then next four bytes are read and position will move to 7 and finally last two bytes will be read an pointer will be moved to position 9 and stream will end because end of stream is reached.
Caution! Sometimes, mostly while using network streams, when we expect stream to retrieve certain number of bytes we will not retrieve them all, so be careful when reading or writing data and always check if all bytes are written or read.
Is it possible to set pointer at certain position of a stream?
Yes it is, that process is called seeking. Note that MemoryStream andFile stream support it but NetworkStream does not. Also seeking allows us to read from beginning, end or custom location from within a stream.
Do I have to dispose of a Streams?
Yes, you should always dispose of a stream or or use using statement.
This conclude introduction to Streams lets see some examples.
Example of using FileStream:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
using System; using System.IO; namespace Streams { class Program { static void Main(string[] args) { string path = @"d:\csharp\stream.txt"; using (FileStream fs = File.Create(path)) { // It is always good practice // to check if we can read or write to a stream if (!fs.CanRead || !fs.CanWrite) return; // To get Current position // we use long type because // FileStream.Position method // returns us long type long startPosition = fs.Position; Console.WriteLine("Position at the start of a stream is: {0}", startPosition); // Inside byte array we store bytes // that we want to save // to a file byte[] byteArray = { 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113 }; // Write function expects 3 parameters: // bytes to write // Position at which we will start storing bytes // Maximum number of bytes to write in one chunk fs.Write(byteArray, 0, byteArray.Length); long currentPosition = fs.Position; // Note that result will be 14 // Although we have written 14 bytes // Starting position was 0, so 0 position was first to be filled // so when byte "113" was written, position was incremented by 1 Console.WriteLine("Position at the end of a writing to a stream is: {0}", currentPosition); // Because Stream is at position 5 // we need to reset position manually // so that we can read it again from the start fs.Position = 0; // To read stream we need a new byte array // to verify that all bytes were written byte[] newByteArray = new byte[fs.Length]; // FileStream.Read method is used to read from a stream // FileStream.Read method has a int return type // so we can use it to get number of bytes read // and verify that entire stream is read int allBytesRead = fs.Read(newByteArray, 0, newByteArray.Length); // You can triger this exception if you change third parameter // of fs.Read method to be less than bytes written if (allBytesRead != byteArray.Length) { throw new Exception("Number of bytes read is not equal to number of bytes written."); } // We can use Seek method to get stream position from // the Begining of a Stream long positionFive = fs.Seek(5, SeekOrigin.Begin); // We can use Seek method to get stream position from // the current position +/- number of places long positionSix = fs.Seek(7, SeekOrigin.Current); // We can use Seek method to get stream position from // the end position +/- number of places long positionLenghtOfAStreamPlusTen = fs.Seek(-10, SeekOrigin.End); Console.WriteLine(""); } } } } |