0% found this document useful (0 votes)
7 views

Lect Note On Chapter 4 - Part I - File I-O

Uploaded by

beshahashenafi32
Copyright
© © All Rights Reserved
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views

Lect Note On Chapter 4 - Part I - File I-O

Uploaded by

beshahashenafi32
Copyright
© © All Rights Reserved
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
You are on page 1/ 25

File Input/output systems

 Examines I/O-related topics as seen in .NET Framework


o First explore type defined in System.IO namespace
o How programmatically modify a machine’s directory and file structure.
o Various ways to read from and write to:
 character-based, binary-based, string-based, and memory-based data
stores.

Exploring the System.IO Namespace


 base class libraries devoted to file-based (and memory-based) input and output
(I/O) services.
 defines a set of classes, interfaces, enumerations, structures, and delegates
 types used for programmatic manipulation of physical directories and files.
 Additional types support to read data from and write data to string buffers as well
as raw memory locations.

Key Members of the System.IO Namespace – non abstract classes


Nonabstract I/O Class Meaning in Life
Type
BinaryReader, Types allow you to store and retrieve primitive data types (integers,
BinaryWriter Booleans, strings, and whatnot) as a binary value.
BufferedStream Type provides temporary storage for a stream of bytes that may be
committed to storage at a later time.
Directory, DirectoryInfo Types are used to manipulate a machine’s directory structure.
 Directory type exposes functionality using static members.
 DirectoryInfo type exposes similar functionality from a valid
object reference.
DriveInfo Type provides detailed information regarding the drives used
by a given machine.
Types are used to manipulate a machine’s set of files.
 File type exposes functionality using static members.
File, FileInfo
Organized by Teshome A. Page 1
 FileInfo type exposes similar functionality from a valid
object reference.
FileStream Type allows for random file access (e.g., seeking capabilities)
with data represented as a stream of bytes.
FileSystemWatcher Type allows you to monitor the modification of external files
in a specified directory.
MemoryStream Type provides random access to streamed data stored in
memory rather than a physical file.
Path Type performs operations on System.String types that contain
file or directory path information in a platform-neutral
manner.
StreamWriter, Types are used to store (and retrieve) textual information to
StreamReader (or from) a file. These types do not support random file
access.
StringWriter, Like the StreamReader/StreamWriter types, these classes also
StringReader work with textual information. However, the underlying
storage is a string buffer rather than a physical file.
 In addition, System.IO defines a number of enumerations, as well as a set of
abstract classes (Stream, TextReader, TextWriter, and so forth).

The Directory(Info) and File(Info) Types


 Four types - allow to manipulate individual files /a machine’s directory structure.
 Directory and File - expose creation, deletion, copying, and moving operations
using various static members.
 FileInfo and DirectoryInfo - expose similar functionality as instance-level
methods – object must be instantiated first.
 Directory and File types directly extend System.Object, while DirectoryInfo and
FileInfo derive from the abstract FileSystemInfo type.
 Generally speaking, FileInfo and DirectoryInfo are better choices for obtaining full
details of a file or directory (e.g., time created, read/write capabilities, etc.), as
their members tend to return strongly typed objects.
 In contrast, the Directory and File class members tend to return simple string
values rather than strongly typed objects.

Organized by Teshome A. Page 2


 The DirectoryInfo and FileInfo types receive many behaviors from the abstract
FileSystemInfo base class.

Some core properties of FileSystemInfo


Property Meaning in Life
Attributes Gets or sets the attributes associated with the current file
that are represented by the FileAttributes enumeration
CreationTime Gets or sets the time of creation for the current file or
directory
Exists Can be used to determine whether a given file or directory
exists
Extension Retrieves a file’s extension
FullName Gets the full path of the directory or file
LastAccessTime Gets or sets the time the current file or directory was last
accessed
LastWriteTime Gets or sets the time when the current file or directory was
last written to
Name Obtains the name of the current file or directory
Delete( ) but implemented by derived types to delete a given file/
directory

Working with the DirectoryInfo Type


 Creatable I/O-centric type – object is required
 Contains a set of members used for creating, moving, deleting, and enumerating
over directories and subdirectories.
 Contain members inherited from FileSystemInfo + its own.

Key Members of the DirectoryInfo Type

Member Meaning in Life


Create(), CreateSubdirectory() Create a directory (or set of subdirectories), given a
path name
Delete() Deletes a directory and all its contents
GetDirectories() Returns an array of strings that represent all
subdirectories in the current directory
GetFiles() Retrieves an array of FileInfo types that represent a set
of files in the given directory
MoveTo() Moves a directory and its contents to a new path

Organized by Teshome A. Page 3


Parent Retrieves the parent directory of the specified path
Root Gets the root portion of a path
 “.” Used to obtain access to the current working directory (i.e., the directory of the
executing application):

// Bind to the current working directory.


DirectoryInfo dir1 = new DirectoryInfo(".");
// Bind to C:\Windows, // using a verbatim string.
DirectoryInfo dir2 = new DirectoryInfo(@"C:\Windows"); //”C:\\Windows”

 The argument “C:\Windows” assume that the path passed into the constructor
already exists on the physical machine.
 Otherwise, attempting to interact with a nonexistent directory result in
System.IO.DirectoryNotFoundException error.
 The following will create a director in the specified location:
// Bind to a nonexistent directory, then create it.
DirectoryInfo dir3 = new DirectoryInfo(@"C:\MyCode\Testing");
dir3.Create();

 Once a DirectoryInfo object is created, the underlying directory contents can be


investigated using any of the properties inherited from FileSystemInfo.
 The following console application illustrate the issue:

class Program
{
static void Main(string[] args)
{
Console.WriteLine("***** Fun with Directory(Info) *****\n");
ShowWindowsDirectoryInfo();
Console.ReadLine();
}
static void ShowWindowsDirectoryInfo()
{ // Dump directory information.
DirectoryInfo dir = new DirectoryInfo(@"C:\Windows");
Console.WriteLine("***** Directory Info *****");
Console.WriteLine("FullName: {0}", dir.FullName);
Console.WriteLine("Name: {0}", dir.Name);
Console.WriteLine("Parent: {0}", dir.Parent);
Console.WriteLine("Creation: {0}", dir.CreationTime);
Console.WriteLine("Attributes: {0}", dir.Attributes);
Console.WriteLine("Root: {0}", dir.Root);
Console.WriteLine("**************************\n"); }
}
Organized by Teshome A. Page 4
Enumerating Files with the DirectoryInfo Type

 Beyond obtaining basic details of an existing directory…


 Use the GetFiles( ) method to obtain information about all files in that specific
directory (such as *.jpg or others).
 GetFiles() returns an array of FileInfo types, each of which exposes details of a
particular file.
 The following code illustrate the issue:

static void DisplayImageFiles()


{
DirectoryInfo dir = new DirectoryInfo(@"C:\Windows\Web\Wallpaper");
// Get all files with a *.jpg extension.
FileInfo[] imageFiles = dir.GetFiles("*.xls");
// How many were found?
Console.WriteLine("Found {0} *.jpg files\n", imageFiles.Length);
// Now print out info for each file.
foreach (FileInfo f in imageFiles) {
Console.WriteLine("***************************");
Console.WriteLine("File name: {0}", f.Name);
Console.WriteLine("File size: {0}", f.Length);
Console.WriteLine("Creation: {0}", f.CreationTime);
Console.WriteLine("Attributes: {0}", f.Attributes);
Console.WriteLine("***************************\n"); }
}

Creating Subdirectories with the DirectoryInfo Type

 CreateSubdirectory() – method used to extend a directory structure.


 Create a single subdirectory, as well as multiple nested subdirectories, in a single
function call.
 Illustration is given below:

static void ModifyAppDirectory()


{

Organized by Teshome A. Page 5


DirectoryInfo dir = new DirectoryInfo(".");
// Create \MyFolder off application directory.
dir.CreateSubdirectory("MyFolder");
// Create \MyFolder2\Data off application directory.
dir.CreateSubdirectory(@"MyFolder2\Data");
}

 CreateSubdirectory() method return a value of type DirectoryInfo representing the


newly created item is passed back on successful execution.
 Consider the following update:

static void ModifyAppDirectory()


{
DirectoryInfo dir = new DirectoryInfo(".");
// Create \MyFolder off initial directory.
dir.CreateSubdirectory("MyFolder");
// Capture returned DirectoryInfo object.
DirectoryInfo myDataFolder = dir.CreateSubdirectory(@"MyFolder2\Data");
// Prints path to ..\MyFolder2\Data.
Console.WriteLine("New Folder is: {0}", myDataFolder);
}

Working with the Directory Type


 The static members of Directory mimic the functionality provided by the instance-
level members defined by DirectoryInfo.
 The members of Directory typically return string types rather than strongly typed
FileInfo/DirectoryInfo types.
 The following example demonstrate how to displays the names of all drives
mapped to the current computer (via the Directory.GetLogicalDrives() method)
and uses the static Directory.Delete() method to remove the \MyFolder and \
MyFolder2\Data subdirectories previously created:

static void FunWithDirectoryType()


{
// List all drives on current computer.
string[] drives = Directory.GetLogicalDrives();
Console.WriteLine("Here are your drives:");
foreach (string s in drives)
Console.WriteLine("--> {0} ", s);
// Delete what was created.
Console.WriteLine("Press Enter to delete directories");

Organized by Teshome A. Page 6


Console.ReadLine();
try {
Directory.Delete(string.Format(@"{0}\MyFolder", Environment.CurrentDirectory));
// The second parameter specifies whether you wish to destroy any subdirectories.
Directory.Delete(string.Format(@"{0}\MyFolder2",Environment.CurrentDirectory),
true); }
catch (IOException e)
{
Console.WriteLine(e.Message);
}
}

Working with the DriveInfo Class Type


 The System.IO namespace provides a class named DriveInfo.
 Like Directory.GetLogicalDrives(), the static DriveInfo.GetDrives() method
allows you to discover the names of a machine’s drives.
 DriveInfo also provides numerous other details (such as the drive type, available
free space, volume label, and whatnot).
 Illustration program:

class Program
{
static void Main(string[] args) {
Console.WriteLine("***** Fun with DriveInfo *****\n");
// Get info regarding all drives.
DriveInfo[] myDrives = DriveInfo.GetDrives();
// Now print drive stats.
foreach(DriveInfo d in myDrives)
{ Console.WriteLine("Name: {0}", d.Name); Console.WriteLine("Type: {0}",
d.DriveType);
// Check to see whether the drive is mounted.
if (d.IsReady) {
Console.WriteLine("Free space: {0}", d.TotalFreeSpace);
Console.WriteLine("Format: {0}", d.DriveFormat);
Console.WriteLine("Label: {0}", d.VolumeLabel);
Console.WriteLine();
}
} Console.ReadLine();
}}
 At this point, you have investigated some core behaviors of the Directory,
DirectoryInfo, and DriveInfo classes. Next, you’ll learn how to create, open, close,
and destroy the files that populate a given directory.
Organized by Teshome A. Page 7
Working with the FileInfo Class
 The FileInfo class allows to obtain details regarding existing files on your hard
drive (time created, size, file attributes, and so forth) and aids in the creation,
copying, moving, and destruction of files.
 FileInfo class contain functionality inherited from FileSystemInfo + its own.

FileInfo Core Members

Member Meaning in Life

AppendText() Creates a StreamWriter type (described later) that appends


text to a file CopyTo() Copies an existing file to a new file
Create() Creates a new file and returns a FileStreamtype
(described later) to interact with the newly created file

CreateText() Creates a StreamWriter type that writes a new text file

Delete() Deletes the file to which a FileInfo instance is bound

Directory Gets an instance of the parent directory

DirectoryName Gets the full path to the parent directory

Length Gets the size of the current file or directory

MoveTo() Moves a specified file to a new location, providing the


option to specify a new file name

Name Gets the name of the file

Open() Opens a file with various read/write and sharing privileges

OpenRead() Creates a read-only FileStream

OpenText() Creates a StreamReader type that reads from an existing


text file

OpenWrite() Creates a write-only FileStream type

Organized by Teshome A. Page 8


 Note: majority of the methods of the FileInfo class return a specific I/O-centric
object (FileStream, StreamWriter, and so forth) that allows you to begin reading
and writing data to (or reading from) the associated file in a variety of formats.
 The following illustrate various ways to obtain a file handle using the FileInfo
class type.

The FileInfo.Create() Method

 The first way you can create a file handle is to make use of the FileInfo.Create()
method:

static void Main(string[] args) {


// Make a new file on the C drive.
FileInfo f = new FileInfo(@"C:\Test.dat");
FileStream fs = f.Create();
// Use the FileStream object...
// Close down file stream.
fs.Close();
}

 Notice that the FileInfo.Create() method returns a FileStream type, which exposes
synchronous and asynchronous write/read operations to/from the underlying file
 The FileStream object returned by FileInfo.Create() grants full read/write access to
all users.
 At the end make sure to close down the handle to release the underlying
unmanaged resources of the stream.

static void Main(string[] args) {


// Defining a 'using scope' for file I/O types is ideal.
FileInfo f = new FileInfo(@"C:\Test.dat");
using (FileStream fs = f.Create())
{
// Use the FileStream object... } }
The FileInfo.Open() Method
 Used to open existing files as well as create new files with far more precision
than FileInfo.Create(), given that Open()typically takes several parameters to
qualify the overall structure of the file you are manipulating.
 Once the call to Open() completes, you are returned a FileStream object.
Consider the following logic:

Organized by Teshome A. Page 9


static void Main(string[] args) {

// Make a new file via FileInfo.Open().

FileInfo f2 = new FileInfo(@"C:\Test2.dat");

using(FileStream fs2 = f2.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite,


FileShare.None)) {

// Use the FileStream object... }

This version of the overloaded Open() method requires three parameters.

 The first parameter specifies the general flavor of the I/O request (e.g., make a
new file, open an existing file, append to a file, etc.), which is specified using
the FileMode enumeration

public enum FileMode { CreateNew, Create, Open, OpenOrCreate, Truncate, Append}


Members of the FileMode Enumeration

Member Meaning in Life

CreateNew Informs the OS to make a new file. If it already exists, an


IOException is thrown. Create Informs the OS to make a
new file. If it already exists, it will be overwritten. Open
Opens an existing file. If the file does not exist, a
FileNotFoundException is thrown.

OpenOrCreate Opens the file if it exists; otherwise, a new file is created.


Truncate Opens a file and truncates the file to 0 bytes in
size.

Append Opens a file, moves to the end of the file, and begins write
operations (this flag can only be used with a write-only
stream). If the file does not exist, a new file is created.

The second parameter, a value from the FileAccess enumeration, is used to determine
the read/write behavior of the underlying stream:

Organized by Teshome A. Page 10


public enum FileAccess { Read, Write, ReadWrite }

 The third parameter, FileShare, which specifies how the file is to be shared
among other file handlers.

public enum FileShare { None, Read, Write, ReadWrite }

The FileInfo.OpenRead() and FileInfo.OpenWrite() Methods


 These methods return a properly configured read-only or write-only FileStream
type, without the need to supply various enumeration values.
 OpenRead() and OpenWrite() return a FileStream object

static void Main(string[] args) {


// Get a FileStream object with read-only permissions.
FileInfo f3 = new FileInfo(@"C:\Test3.dat");
using(FileStream readOnlyStream = f3.OpenRead()) {
// Use the FileStream object...
}
// Now get a FileStream object with write-only permissions.
FileInfo f4 = new FileInfo(@"C:\Test4.dat");
using(FileStream writeOnlyStream = f4.OpenWrite()) {

// Use the FileStream object...

}}

The FileInfo.OpenText() Method

 Another open-centric member - OpenText().


 Unlike the others the OpenText() method returns an instance of the
StreamReader type, not FileStream type.
 The StreamReader type provides a way to read character data from file

static void Main(string[] args) {


// Get a StreamReader object.
FileInfo f5 = new FileInfo(@"C:\boot.ini");
using(StreamReader sreader = f5.OpenText()) {
// Use the StreamReader object...
}}

The FileInfo.CreateText() and FileInfo.AppendText() Methods

 Both CreateText() and AppendText() methods return a StreamWriter reference.


Organized by Teshome A. Page 11
 The StreamWriter type provides a way to write character data to file.
static void Main(string[] args)
{ FileInfo f6 = new FileInfo(@"C:\Test5.txt");
using(StreamWriter swriter = f6.CreateText()) {
// Use the StreamWriter object...
}
FileInfo f7 = new FileInfo(@"C:\FinalTest.txt");
using(StreamWriter swriterAppend = f7.AppendText()) {
// Use the StreamWriter object...
}}

Working with the File Type


 The File type provides functionality almost identical to that of the FileInfo type,
using a number of static members.
 It includes - FileInfo, Filesupplies AppendText(), Create(), CreateText(), Open(),
OpenRead(), OpenWrite(), and OpenText() methods.
 In many cases, the File and FileInfo types may be used interchangeably.
 To illustrate, each of the previous FileStream examples can be simplified by using
the File type instead:

static void Main(string[] args) {


// Obtain FileStream object via File.Create().
using(FileStream fs = File.Create(@"C:\Test.dat")) { }
// Obtain FileStream object via File.Open().
using(FileStream fs2 = File.Open(@"C:\Test2.dat", FileMode.OpenOrCreate,
FileAccess.ReadWrite, FileShare.None)) { }
// Get a FileStream object with read-only permissions.
using(FileStream readOnlyStream = File.OpenRead(@"Test3.dat")) { }
// Get a FileStream object with write-only permissions.
using(FileStream writeOnlyStream = File.OpenWrite(@"Test4.dat")) { }
// Get a StreamReader object.
using(StreamReader sreader = File.OpenText(@"C:\boot.ini")) { }
// Get some StreamWriters.
using(StreamWriter swriter = File.CreateText(@"C:\Test3.txt")) { }
using(StreamWriter swriterAppend = File.AppendText(@"C:\FinalTest.txt")) { }
}

Additional File-centric Members


 A few unique members supported by the File type, which can greatly simplify the
processes of reading and writing textual data.

Organized by Teshome A. Page 12


Table: Methods of the File Type
Method Meaning in Life
ReadAllBytes() Opens the specified file, returns the binary data as an array
of bytes, and then closes the file
ReadAllLines() Opens a specified file, returns the character data as an array
of strings, and then closes the file
ReadAllText() Opens a specified file, returns the character data as a
System.String, and then closes the file
WriteAllBytes() Opens the specified file, writes out the byte array, and then
closes the file
WriteAllLines() Opens a specified file, writes out an array of strings, and
then closes the file
WriteAllText() Opens a specified file, writes the character data, and then
closes the file
 Using these new methods of the File type, you are able to read and write batches of
data in just a few lines of code.
 Even better, each of these new members automatically closes down the underlying
file handle.
 For example, the following console program (named SimpleFileIO) will persist the
string data into a new file on the C drive (and read it into memory) with minimal
fuss:

using System; using System.IO;


class Program
{
static void Main(string[] args) {
Console.WriteLine("***** Simple IO with the File Type *****\n");
string[] myTasks = { "Fix bathroom sink", "Call Dave", "Call Mom and
Dad", "Play Xbox 360"};
// Write out all data to file on C drive.
File.WriteAllLines(@"C:\tasks.txt", myTasks);
// Read it all back and print out.
foreach (string task in File.ReadAllLines(@"C:\tasks.txt")) {
Console.WriteLine("TODO: {0}", task); }
Console.ReadLine();
}}

 Clearly, when you wish to quickly obtain a file handle, the File type will save you
some keystrokes.

Organized by Teshome A. Page 13


 However, one benefit of first creating a FileInfo object is that you are able to
investigate the file using the members of the abstract FileSystemInfo base class.

The Abstract Stream Class


 At this point, you have seen numerous ways to obtain FileStream, StreamReader,
and StreamWriter objects, but you have yet to read data from, or write data to, a
file using these types.
 To understand how to do so, you’ll need to become familiar with the concept of a
stream.
 In the world of I/O manipulation, a stream represents a chunk of data flowing
between a source and a destination.
 Streams provide a common way to interact with a sequence of bytes, regardless of
what kind of device (file, network connection, printer, etc.) is storing or displaying
the bytes in question.
 The abstract System.IO.Stream class defines a number of members that provide
support for synchronous and asynchronous interactions with the storage medium
(e.g., an underlying file or memory location).
 Figure shows various descendents of the Stream type, seen through the eyes of the
Visual Studio 2008 Object Browser.

Organized by Teshome A. Page 14


 Note: Be aware that the concept of a stream is not limited to files IO. To be sure,
the .NET libraries provide stream access to networks, memory locations, and other
stream-centric abstractions.
 Again, Stream descendents represent data as a raw stream of bytes; therefore,
working directly with raw streams can be quite cryptic.
 Some Stream-derived types support seeking, which refers to the process of
obtaining and adjusting the current position in the stream.
 To begin understanding the functionality provided by the Stream class, take note
of the core members described below.

Table: Abstract Stream Members

Member Meaning in Life

CanRead, CanWrite Determine whether the current stream supports reading,


seeking, and/or CanSeekwriting.

Close() Closes the current stream and releases any resources (such
as sockets and file handles) associated with the current
stream. Internally, this method is aliased to the Dispose()
method; therefore “closing a stream” is functionally
equivalent to “disposing a stream.”

Flush() Updates the underlying data source or repository with the


current state of the buffer and then clears the buffer. If a
stream does not implement a buffer, this method does
nothing.

Length Returns the length of the stream, in bytes.

Position Determines the position in the current stream.

Read(), ReadByte() Read a sequence of bytes (or a single byte) from the current
stream and advance the current position in the stream by
the number of bytes read.

Seek() Sets the position in the current stream.

SetLength() Sets the length of the current stream.

Organized by Teshome A. Page 15


Write(), WriteByte() Write a sequence of bytes (or a single byte) to the current
stream and advance the current position in this stream by
the number of bytes written.

Working with FileStreams

 provides an implementation for the abstract Stream members - for file-based


streaming.
 fairly primitive stream; read/ write only a single byte or an array of bytes.
 not often need to directly interact with the members of the FileStream type.
 Use various stream wrappers - easier to work with textual data or .NET types.
 Ex. the synchronous read/write capabilities of the FileStreamtype.
 Assume - Application named FileStreamApp.
 Your goal is to write a simple text message to a new file named myMessage.dat.
 However, given that FileStream can operate only on raw bytes, you will be
required to encode the System.String type into a corresponding byte array.
 Luckily, the System.Text namespace defines a type named Encoding, which
provides members that encode and decode strings to (or from) an array of bytes.
 Once encoded, the byte array is persisted to file using the FileStream.Write()
method.
 To read the bytes back into memory, you must reset the internal position of the
stream (via the Position property) and call the ReadByte() method.
 Finally, you display the raw byte array and the decoded string to the console.
 Here is the complete Main() method:

// Don't forget to import the System.Text and System.IO namespaces.


static void Main(string[] args) {
Console.WriteLine("***** Fun with FileStreams *****\n");
// Obtain a FileStream object.
using(FileStream fStream = File.Open(@"C:\myMessage.dat", FileMode.Create))
{
// Encode a string as an array of bytes.
string msg = "Hello!";

Organized by Teshome A. Page 16


byte[] msgAsByteArray = Encoding.Default.GetBytes(msg);
// Write byte[] to file.
fStream.Write(msgAsByteArray, 0, msgAsByteArray.Length);
// Reset internal position of stream.
fStream.Position = 0;
// Read the types from file and display to console.
Console.Write("Your message as an array of bytes: ");
byte[] bytesFromFile = new byte[msgAsByteArray.Length];
for (int i = 0; i < msgAsByteArray.Length; i++) {
bytesFromFile[i] = (byte) fStream.ReadByte();
Console.Write(bytesFromFile[i]); }
// Display decoded messages.
Console.Write("\nDecoded Message: ");
Console.WriteLine(Encoding.Default.GetString(bytesFromFile));
}
Console.ReadLine();
}
 While this example does indeed populate the file with data, it punctuates the major
downfall of working directly with the FileStream type: it demands to operate on
raw bytes.
 Other Stream-derived types operate in a similar manner. For example, if you wish
to write a sequence of bytes to a region of memory, you can allocate a
MemoryStream.
 Likewise, if you wish to push an array of bytes through a network connection, you
can make use of the NetworkStream type.

Working with StreamWriters and StreamReaders


 The StreamWriter and StreamReader classes are useful whenever you need to read
or write character-based data (e.g., strings).
 Both of these types work by default with Unicode characters; however, you can
change this by supplying a properly configured System.Text.Encoding object
reference.
 To keep things simple, let’s assume that the default Unicode encoding fits the bill.
 StreamReader derives from an abstract type named TextReader, as does the related
StringReader type
 The TextReader base class provides a very limited set of functionality to each of
these descendents, specifically the ability to read and peek into a character stream.

Organized by Teshome A. Page 17


 The StreamWriter type (as well as StringWriter) derives from an abstract base
class named TextWriter.
 This class defines members that allow derived types to write textual data to a given
character stream.
 To aid in your understanding of the core writing capabilities of the StreamWriter
and StringWriter classes, the core members of the abstract TextWriter base class
are described below.

Table: Core Members of TextWriter

Member Meaning in Life

Close() This method closes the writer and frees any associated resources.
In the process, the buffer is automatically flushed (again,
this member is functionally equivalent to calling the Dispose()
method).

Flush() This method clears all buffers for the current writer and causes
any buffered data to be written to the underlying device,
but does not close the writer.

NewLine This property indicates the newline constant for the derived writer
class. The default line terminator for the Windows OS is a
carriage return followed by a line feed (\r\n).

Write() This overloaded method writes data to the text stream without a
newline constant.

WriteLine() This overloaded method writes data to the text stream with a
newline constant.

 Note: The last two members of the TextWriter class probably look familiar to you.
If you recall, the System.Console type has Write() and WriteLine() members that
push textual data to the standard output device.

In fact, the Console.In property wraps a TextWriter, and the Console.Out property
wraps a TextReader.

Organized by Teshome A. Page 18


 The derived StreamWriter class provides an appropriate implementation for the
Write(), Close(), and Flush() methods, and it defines the additional AutoFlush
property.
 This property, when set to true, forces StreamWriter to flush all data every time
you perform a write operation.
 Be aware that you can gain better performance by setting AutoFlush to false,
provided you always call Close() when you are done writing with a StreamWriter.

Writing to a Text File

 To see the StreamWriter type in action, create a new Console Application named
StreamWriterReaderApp.
 The following Main() method creates a new file named reminders.txt using the
File.CreateText() method.
 Using the obtained StreamWriter object, you add some textual data to the new file,
as shown here:

static void Main(string[] args) {


Console.WriteLine("***** Fun with StreamWriter / StreamReader *****\n");
// Get a StreamWriter and write string data.
using(StreamWriter writer = File.CreateText("reminders.txt"))
{
writer.WriteLine("Don't forget Mother's Day this year...");
writer.WriteLine("Don't forget Father's Day this year...");
writer.WriteLine("Don't forget these numbers:");
for(int i = 0; i < 10; i++)
writer.Write(i + " ");
// Insert a new line.
writer.Write(writer.NewLine);
}
Console.WriteLine("Created file and wrote some thoughts...");
Console.ReadLine();
}
 Once you run this program, you can examine the contents of this new file. You
will find this file under the bin\Debug folder of your current application, given that
you have not specified an absolute path at the time you called CreateText().

Reading from a Text File

Organized by Teshome A. Page 19


 Now you need to understand how to programmatically read data from a file using
the corresponding StreamReader type.
 This class derives from the abstract TextReader, which offers the functionality
described below.

Table: TextReader Core Members

Member Meaning in Life

Peek() Returns the next available character without actually changing the
position of the reader. A value of -1 indicates you are at the end of
the stream.

Read() Reads data from an input stream.

ReadBlock() Reads a maximum of count characters from the current stream and
writes the data to a buffer, beginning at index.

ReadLine() Reads a line of characters from the current stream and returns the
data as a string (a null string indicates EOF).

ReadToEnd() Reads all characters from the current position to the end of the
stream and returns them as a single string.

 Illustration: read in the textual data from the reminders.txt file as shown here:

static void Main(string[] args) {


Console.WriteLine("***** Fun with StreamWriter / StreamReader *****\
n"); ...
// Now read data from file.
Console.WriteLine("Here are your thoughts:\n");
using(StreamReader sr = File.OpenText("reminders.txt")) {
string input = null;
while ((input = sr.ReadLine()) != null) {
Console.WriteLine (input);
} } Console.ReadLine();
}

 Once you run the program, you will see the character data within reminders.txt
displayed to the console.

Organized by Teshome A. Page 20


Directly Creating StreamWriter/StreamReader Types

 One of the slightly confusing aspects of working with the types within System.IO
is that you can often achieve an identical result using numerous approaches.
 For example, you have already seen that you can obtain a StreamWriter via the
File or FileInfo type using the CreateText() method.
 In reality, there is yet another way in which you can work with StreamWriters and
StreamReaders: create them directly.
 For example, the current application could be retrofitted as follows:

static void Main(string[] args) {


Console.WriteLine("***** Fun with StreamWriter / StreamReader *****\n");
// Get a StreamWriter and write string data.
using(StreamWriter writer = new StreamWriter("reminders.txt")) { ... }
// Now read data from file.
using(StreamReader sr = new StreamReader("reminders.txt")) { ... }
}
 Although it can be a bit confusing to see so many seemingly identical approaches
to file I/O, keep in mind that the end result is greater flexibility. In any case, now
that you have seen how to move character data to and from a given file using the
StreamWriter and StreamReader types.

Working with StringWriters and StringReaders


 Using the StringWriter and StringReader types, you can treat textual information
as a stream of in-memory characters.
 This can prove helpful when you wish to append character-based information to an
underlying buffer.
 Illustrate: Console Application (named StringReaderWriterApp) writes a block of
string data to a StringWriter object rather than a file on the local hard drive:

static void Main(string[] args) {


Console.WriteLine("***** Fun with StringWriter / StringReader *****\n");
// Create a StringWriter and emit character data to memory.
using(StringWriter strWriter = new StringWriter())
{
strWriter.WriteLine("Don't forget Mother's Day this year...");
// Get a copy of the contents (stored in a string) and pump
// to console.

Organized by Teshome A. Page 21


Console.WriteLine("Contents of StringWriter:\n{0}", strWriter);
}
Console.ReadLine();
}

 Because StringWriter and StreamWriter both derive from the same base class
(TextWriter), the writing logic is more or less identical.
 However, given that nature of StringWriter, be aware that this class allows you to
extract a System.Text.StringBuilder object via the GetStringBuilder() method:

using (StringWriter strWriter = new StringWriter())


{
strWriter.WriteLine("Don't forget Mother's Day this year...");
Console.WriteLine("Contents of StringWriter:\n{0}", strWriter);
// Get the internal StringBuilder.
StringBuilder sb = strWriter.GetStringBuilder();
sb.Insert(0, "Hey!! ");
Console.WriteLine("-> {0}", sb.ToString());
sb.Remove(0, "Hey!! ".Length);
Console.WriteLine("-> {0}", sb.ToString());
}

 When you wish to read from a stream of character data, make use of the
corresponding StringReader type, which (as you would expect) functions
identically to the related StreamReader class.
 In fact, the StringReader class does nothing more than override the inherited
members to read from a block of character data, rather than a file, as shown here:

using (StringWriter strWriter = new StringWriter())


{
strWriter.WriteLine("Don't forget Mother's Day this year...");
Console.WriteLine("Contents of StringWriter:\n{0}", strWriter);
// Read data from the StringWriter.
using (StringReader strReader = new StringReader(strWriter.ToString()))
{ string input = null;
while ((input = strReader.ReadLine()) != null)
{
Console.WriteLine(input);
}
}
}

Working with BinaryWriters and BinaryReaders


Organized by Teshome A. Page 22
 Another writer/reader sets are BinaryReader and BinaryWriter, both of which
derive directly from System.Object.
 These types allow you to read and write discrete data types to an underlying stream
in a compact binary format.
 The BinaryWriter class defines a highly overloaded Write() method to place a data
type in the underlying stream.
 In addition to Write(), BinaryWriter provides additional members that allow you to
get or set the Stream-derived type and offers support for random access to the data

Table BinaryWriter Core Members

Member Meaning in Life

BaseStream This read-only property provides access to the underlying stream


used with the BinaryWriter object.

Close() This method closes the binary stream.

Flush() This method flushes the binary stream.

Seek() This method sets the position in the current stream.

Write() This method writes a value to the current stream.

 The BinaryReader class complements the functionality offered by BinaryWriter.

Table BinaryReader Core Members

Member Meaning in Life

BaseStream This read-only property provides access to the underlying stream


used with the BinaryReader object.

Close() This method closes the binary reader.

PeekChar() This method returns the next available character without actually
advancing the position in the stream.

Read() This method reads a given set of bytes or characters and stores
them in the incoming array.
Organized by Teshome A. Page 23
ReadXXXX() The BinaryReader class defines numerous read methods that grab
the next type from the stream (ReadBoolean(), ReadByte(),
ReadInt32(), and so forth).

 Example: a Console Application named BinaryWriterReader demonestrate writes


of a number of data types to a new *.dat file:

static void Main(string[] args) {


Console.WriteLine("***** Fun with Binary Writers / Readers *****\n");
// Open a binary writer for a file.
FileInfo f = new FileInfo("BinFile.dat");
using(BinaryWriter bw = new BinaryWriter(f.OpenWrite())) {
// Print out the type of BaseStream.
// (System.IO.FileStream in this case).
Console.WriteLine("Base stream is: {0}", bw.BaseStream);
// Create some data to save in the file
double aDouble = 1234.67;
int anInt = 34567;
string aString = "A, B, C";
// Write the data
bw.Write(aDouble);
bw.Write(anInt);
bw.Write(aString);
}
Console.ReadLine(); }

 Notice how the FileStream object returned from FileInfo.OpenWrite() is passed to


the constructor of the BinaryWriter type.
 Using this technique, it is very simple to “layer in” a stream before writing out the
data.
 Do understand that the constructor of BinaryWriter takes any Stream-derived type
(e.g., FileStream, MemoryStream, or BufferedStream). Thus, if you would rather
write binary data to memory, simply supply a valid MemoryStreamobject.
 To read the data out of the BinFile.dat file, the BinaryReader type provides a
number of options.
 Call various read-centric members to pluck each chunk of data from the file
stream:

static void Main(string[] args) { ...


FileInfo f = new FileInfo("BinFile.dat");
...

Organized by Teshome A. Page 24


// Read the binary data from the stream.
using(BinaryReader br = new BinaryReader(f.OpenRead()))
{ Console.WriteLine(br.ReadDouble());
Console.WriteLine(br.ReadInt32());
Console.WriteLine(br.ReadString());
} Console.ReadLine();
}

Organized by Teshome A. Page 25

You might also like