Monday 15 May 2017

Streams 03 Stream Readers & Writers

Now we can't discus streams without mentionig stream readers and writers. They are used to read and write encoded characters to and from streams. the following are stream readers & writers:
  • BinaryReader, BinaryWriter - used for binary (boolean) values 
  • StreamReader, StreamWriter - used for character using encoded values to convert to and from bytes (UTF-8) by defualut 
  • StringReader, StringWriter - used to deal with strings
  • TextReader, TextWriter - Abstract base classes 
The Standard methods for using streams are
  • Close: closes the reader and the stream 
  • Peek looks at the next char 
  • Read(Char[], int32, int32) reads the specifed number of chars into the array 
  • ReadBlock(Char[], Int32, Int32) ReadLine reads a line 
  • ReadToEnd reads the remainder of the reader
Now let's take a look at our stream reader and writer

using System;
using System.IO;
using System.Text;

namespace pc.StreamReadWriteExample
{
    class Program
    {
        static void Main(string[] args)
        {
            var data = "hello world this is some test data";
            byte[] bData = Encoding.Default.GetBytes(data);
            byte[] uData = new byte[bData.Length];

            using (var ms = new MemoryStream(bData, true))
            using (var sr = new StreamReader(ms))
            {
                var b = sr.Read();
                while (b > -1)
                {
                    Console.Write((char)b);
                    b = sr.Read();
                }
            }
            Console.WriteLine("\n");
            using (var ms = new MemoryStream(uData))
            using (var sw = new StreamWriter(ms))
                for (int i = 0; i < bData.Length; i++)
                    sw.Write((char)(bData[i] - 32));

            Console.WriteLine(Encoding.Default.GetString(uData));
        }
    }
}


the first block is pretty straight forward we create a new memory stream with our bData byte array, then we use a StreamReader to access our byte array one byte at a time and we output it to the console.

Secondly we create a memory stream with our uData byte array, this uData is an empty array that's been instantiated to have the same amount of space as the bData array. We then iterate over each element  in the bData array and decrease it by 32 (the ascii difference between uppercase and lower case letters), then using the stream writer we write it back to our memory stream which places our value in the uData byte array. then we output the content of our uData byte array as a string to the console.

The binary reader and writer simplify the process of writing and reading primitive datatypes to and from streams.

using System.Text;
using System.IO;

namespace pc.BinaryReaderExample
{
    class Program
    {
        static void Main(string[] args)
        {
            var intData = new int[] { 1, 2, 3, 4, 5, 6 };
            var boolData = new bool[] { true, true, false, true };
            var charData = new char[] { ' ', 'w', 'o', 'o', 't' };
            var data = "hello world this is test data";
            var byteMessage = Encoding.Default.GetBytes(data);
            var path = @"c:\dev\helloworld.data";

            using (var fs = new FileStream(path, FileMode.Create, FileAccess.ReadWrite))
            using (var bw = new BinaryWriter(fs))
            {
                for (int i = 0; i < intData.Length; i++)
                    bw.Write(intData[i]);

                for (int i = 0; i < boolData.Length; i++)
                    bw.Write(boolData[i]);

                for (int i = 0; i < byteMessage.Length; i++)
                    bw.Write(byteMessage[i]);

                for (int i = 0; i < charData.Length; i++)
                    bw.Write(charData[i]);
            }

            using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read))
            using (var br = new BinaryReader(fs))
            {
                fs.Position = 0;
               
                for (int i = 0; i < intData.Length; i++)
                    System.Console.Write(br.ReadInt32());
                System.Console.WriteLine("\n");

                for (int i = 0; i < boolData.Length; i++)
                    System.Console.Write(br.ReadBoolean()+ " ");
                System.Console.WriteLine("\n");

                for (int i = 0; i < byteMessage.Length; i++)
                    System.Console.Write((char)br.Read());
                System.Console.WriteLine("\n");

                for (int i = 0; i < charData.Length; i++)
                    System.Console.Write(br.ReadChar());
                System.Console.WriteLine("\n");
            }
        }
    }
}


now remember all data is just bits grouped into bytes, so for example if you used a readChar function on data that was say a decimal you'll still get something, just not what you expect. it's up to you to ensure that you're using the appropriate read method with the appropriate bytes.