Files and Directories

Using Streams

A stream is an ordered sequence of bytes that can be used to read and write to some form of backing store - this could be a file. You can think of a stream as an abstraction over that backing store.

By treating our input or output sources/targets as streams, we can implement a more generic approach to reading and writing data.

using System; using System.IO; public c...

 

Streams allow for much greater control over how you are reading and writing your data.

 

The Stream class

The Stream class is an abstract class that represents the base set of available methods over all Stream` types. This is the key abstraction that allows us to define operations that work with streams instead of having to implement different and unique APIs for different inputs and outputs.

There a various implementations of the the Stream type, including:

  • FileStream - This allows you to read/write to a file
  • MemoryStream - This allows you to read/write to memory
  • NetworkStream - This allows you to read/write to a network socket.

 

Readers and Writers

Streams are typically designed for reading and writing absolute byte values, but .NET also provides a further set of implementations of readers/writers that support writing values in other formats - converting to bytes as part of the process.

Common implementations are:

  • BinaryReader/BinaryWriter - for reading and writing data primitives in binary format.
  • StreamReader/StreamWriter - for reacing and writing character values in specific encodings.

 

Reading from a file using a FileStream.

Typically when reading a file using the stream approach, the operation consists of two distinct operations:

  1. Obtaining a stream from a file
  2. Creating a reader to read from the stream.

Let's take a look:

var file = new FileStream(@".\StarWars.txt", FileMode.Open);
var reader = new StreamReader(file);

Firstly, we create an instance of our FileStream class. The arguments to the file stream class in the above call, are the path to the file we want to read, and a value for the FileMode enumeration, which controls how the file is opened. We're usingFileMode.Open in this example, becaause we want to open the file for reading.

Next, we create a StreamReader passing in the FileStream instance. The reader will allow us to read the content of a file as strings with a specific encoding.

 
Reading a line from the file

To read a line from the file using a StreamReader, we can use the ReadLine method:

string line = reader.ReadLine();

The read line method allows us to read an entire line (reading up to the carriage return/line feed (CRLF) or combination of line end characters (depending on the operating system). It then advances the stream to the start of the next line, so the next call will continue from where we left off.

If we wanted to read the entire file in one go, we could instead use the ReadToEnd method:

string content = reader.ReadToEnd();

ReadToEnd will read from the current position to the end, which means if you've already done previous reads, it'll continue from the last read position until the end.

 
Closing the reader and file

It is important that you close your stream after you are finished with it, this allows the system to release resources used in accessing the stream. In terms of FileStream, it also removes any file locks.

file.Close();

If you call Close on the StreamReader, this will automatically close the underlying stream:

reader.Close(); // Closes the FileStream

This makes it simpler to control the closure of everything you are using.

 
Reading the file line by line

To read each line of the file, we can use a while loop, checking the reader on each repetition:

while (!reader.EndOfStream)
{
    string line = reader.ReadLine();
    Console.WriteLine(line);
}

The reader provides a EndOfStream property that is set to true if we reach the end of our file. Using this as a condition for a loop allows us to continue reading until this case.

 

Writing to a file using a FileStream.

Much like we can read a file using FileStream, we can also write to a file too.

There are a few more options when it comes to writing a file - depending on whether you want to create a new file, overwriting an existing file, or even to append to it. The code is quite similar though:

var file = new FileStream(@".\StarWars.txt", FileMode.Create);
var writer = new StreamWriter(file);

Much like before, we're opening up our file using a FileStream. The FileMode enumeration we've seen previously offers up a few other options when writing a file:

  • Create - Creates a new file - if the file exists, it is overwritten.
  • CreateNew - Creates a new file, throwing an exception of the file already exists
  • Append - Allows appending to an existing file.

We're going to keep things simple and create a new file using FileMode.Create.

Next, we then create our StreamWriter using our FileStream as the constructor parameter.

 
Writing a line to a file

To write a line to the file using StreamWriter, we can use the WriteLine method.

write.WriteLine("Hello World");

The WriteLine method overload accepts a string argument and converts that to the data which is written to the underlyingStream - in this case, our file.

Remember, it is important to Close the file after you've finished with it:

file.Close();
Writing lines to the file

If we want to write a collection of items to our file, we can easily loop over them:

string[] jedis = new[] { "Luke Skywalker", "Yoda", "Mace Windu" };
foreach (string jedi in jedis)
{
    writer.WriteLine(jedi);    
}

The loop will end with the last item.

Page 10 of 20