Reading and writing with streams

A stream is a sequence of bytes.

There is an abstract class named Stream that represents a stream. There are many classes that inherit from this base class, so they all work the same way. In the following table are some of the common members of the Stream class:

Member

Description

CanRead, CanWrite

This determines whether you can read from and write to the stream

Length, Position

This determines the total number of bytes and the current position within the stream

Dispose()

This closes the stream and releases its resources

Flush()

If the stream has a buffer, then it is cleared and written to the underlying stream

Read(), ReadAsync()

This reads a specified number of bytes from the stream into a byte array and advances the position

ReadByte()

This reads the next byte from the stream and advances the position

Seek()

This moves the position to the specified position (if CanSeek is true)

Write(), WriteAsync()

This writes the contents of a byte array into the stream

WriteByte()

This writes a byte to the stream

Storage streams can be read and written to, and the bytes will be stored in that location.

Reading and writing with streams

Function streams can only be "plugged onto" other streams to add functionality.

Namespace

Class

Description

System.Security.Cryptography

CryptoStream

This encrypts and decrypts the stream

System.IO.Compression

GZipStream, DeflateStream

This compresses and decompresses the stream

System.Net.Security

AuthenticatedStream

This sends credentials across the stream

Although there will be occasions where you need to work with streams at a low level, most often, you can plug helper classes into the chain to make things easier. Here are some helper classes to handle common scenarios:

Reading and writing with streams

Writing to text and XML streams

Add a new console application project named Ch10_Streams.

In Visual Studio 2017, set the solution's start-up project to be the current selection.

Import the System.IO and System.Xml namespaces, statically import the System.Console type, and add the following statement to the Main method:

    // define an array of strings 
    string[] callsigns = new string[] { "Husker", "Starbuck",
    "Apollo", "Boomer", "Bulldog", "Athena", "Helo", "Racetrack" }; 
 
    // define a file to write to using a text writer helper  
    string textFile = @"/Users/markjprice/Code/Ch10_Streams.txt"; 
    // string textFile = @"C:CodeCh10_Streams.txt"; // Windows 
    StreamWriter text = File.CreateText(textFile); 
 
    // enumerate the strings writing each one to the stream 
    foreach (string item in callsigns) 
    { 
      text.WriteLine(item); 
    } 
    text.Dispose(); // close the stream 
 
    // output all the contents of the file to the Console 
    WriteLine($"{textFile} contains {new FileInfo(textFile).Length}
    bytes."); 
    WriteLine(File.ReadAllText(textFile)); 
 
    // define a file to write to using the XML writer helper 
    string xmlFile = @"/Users/markjprice/Code/Ch10_Streams.xml"; 
    // string xmlFile = @"C:CodeCh10_Streams.xml"; 
 
    FileStream xmlFileStream = File.Create(xmlFile); 
    XmlWriter xml = XmlWriter.Create(xmlFileStream,  
      new XmlWriterSettings { Indent = true }); 
 
    // write the XML declaration 
    xml.WriteStartDocument(); 
  
    // write a root element 
    xml.WriteStartElement("callsigns"); 
 
    // enumerate the strings writing each one to the stream 
    foreach (string item in callsigns) 
    { 
      xml.WriteElementString("callsign", item); 
    } 
 
    // write the close root element 
    xml.WriteEndElement(); 
    xml.Dispose(); 
    xmlFileStream.Dispose(); 
 
    // output all the contents of the file to the Console 
    WriteLine($"{xmlFile} contains {new FileInfo(xmlFile).Length}
    bytes."); 
    WriteLine(File.ReadAllText(xmlFile)); 

Run the console application and view the output:

C:CodeCh10_Streams.txt contains 68 bytes.
Husker
Starbuck
Apollo
Boomer
Bulldog
Athena
Helo
Racetrack
C:CodeCh10_Streams.xml contains 320 bytes.
<?xml version="1.0" encoding="utf-8"?>
<callsigns>
<callsign>Husker</callsign>
<callsign>Starbuck</callsign>
 <callsign>Apollo</callsign>
 <callsign>Boomer</callsign>
 <callsign>Bulldog</callsign>
<callsign>Athena</callsign>
<callsign>Helo</callsign>
 <callsign>Racetrack</callsign>
</callsigns>

Compressing streams

XML is relatively verbose, so it takes up more space in bytes than plain text. We can squeeze the XML using a common compression algorithm known as GZIP.

Import the following namespace:

    using System.IO.Compression; 

Add the following code to the end of the Main method:

    // compress the XML output 
    string gzipFilePath = @"/Users/markjprice/Code/Ch10.gzip"; 
    // string gzipFilePath = @"C:CodeCh10.gzip"; // Windows 
 
    FileStream gzipFile = File.Create(gzipFilePath); 
    GZipStream compressor = new GZipStream(gzipFile,
    CompressionMode.Compress); 
    XmlWriter xmlGzip = XmlWriter.Create(compressor); 
    xmlGzip.WriteStartDocument(); 
    xmlGzip.WriteStartElement("callsigns"); 
    foreach (string item in callsigns) 
    { 
      xmlGzip.WriteElementString("callsign", item); 
    } 
    xmlGzip.Dispose(); 
    compressor.Dispose(); // also closes the underlying stream 
 
    // output all the contents of the compressed file to the Console 
    WriteLine($"{gzipFilePath} contains {new
    FileInfo(gzipFilePath).Length} bytes."); 
    WriteLine(File.ReadAllText(gzipFilePath));  
 
    // read a compressed file 
    WriteLine("Reading the compressed XML file:"); 
    gzipFile = File.Open(gzipFilePath, FileMode.Open); 
    GZipStream decompressor = new GZipStream(gzipFile,
    CompressionMode.Decompress); 
    XmlReader reader = XmlReader.Create(decompressor); 
    while (reader.Read()) 
    { 
      // check if we are currently on an element node named callsign 
      if ((reader.NodeType == XmlNodeType.Element) && (reader.Name ==
      "callsign")) 
      { 
        reader.Read(); // move to the Text node inside the element 
        WriteLine($"{reader.Value}"); // read its value 
      } 
    } 
    reader.Dispose(); 
    decompressor.Dispose(); 

Rerun the application and notice that the compressed XML is less than half the size of the same XML without compression:

C:CodeCh10.gzip contains 150 bytes.
▼     ♦ 
{?{??}En?BYjQqf~???????Bj^r~Jf^??RiI??????MrbNNqfz^1?i?QZ??Zd?☼↨@H♣?$
▬%?
&gc?t,?????*????H?????t?&?d??%b??H?aUPbrjIQ"?←?◄?♦ ??9→∟:)
Reading the compressed XML file:
Husker
Starbuck
Apollo
Boomer
Bulldog
Athena
Helo
Racetrack
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.146.178.165