.NET Framework written application is able to run on different platform. Each platform uses a different end-of-line (EOL) character. You want your code to output the correct EOL character without having to write code to handle the EOL character specially for each platform.

When you are first learning the .NET Framework and even for some time after the proper way to read to, write from, or otherwise interact with files can be unclear because the framework provides so many different ways of attacking this problem. How should you determine which approach fits your scenario?

Use file streams to perform various file functions. There are five basic types of built-in file stream manipulation classes that you can use in order to read and/or write to the file stream:

Class Description
FileStream For the most fine-grained control, use FileStream for file manipulation since it provides the most low-level access to the file, and, therefore, the most complex actions become available. Some of these actions are reading and writing files in both synchronous and asynchronous fashions, methods to lock and unlock part or all of a file, seek a particular position in a file, or even read the file as a stream of either characters or bytes.
StreamReader This type is derived from the abstract base class TextReader. The StreamReader class is designed for reading character or string input from a file. This class contains methods to read single characters, blocks of characters, lines of characters, or even the whole file into a single string variable.
StreamWriter This class derives from the TextWriter class. It is designed for writing character or string output to a file. This class contains methods to write single characters or lines of characters.
BinaryReader This type is derived from the Object class, as is the BinaryWriter class. It is designed for reading primitive data types梚ncluding byte or char data梖rom a file. This class contains methods to read any of the simple types (int, long, float, etc.), including char arrays and byte arrays.
BinaryWriter This type derives from the Object class. It is designed for writing primitive data types梚ncluding byte or char data to a file. This class contains methods to write any of the primitive types (int, long, float, etc.), including char arrays and byte arrays.

There are other stream readers and writers (XmlTextReader/Writer, StringReader/Writer) that can also perform file stream functions but at a higher level. This article is meant for a more fundamental approach to file operations.

The most straightforward method of creating an object is to use the new keyword. The FileStream class has several overloaded class constructors that enable creating a new FileStream from scratch. The FileStream’s constructor enables a new FileStream object to be created from either a filename or a file handle.

The FileStream constructor can also accept a FileAccess, FileMode, and/or FileShare enumeration value. These enumeration values are defined in Tables as following.

FileMode enumeration values

Value Name Definition Specifics
Append Opens an existing file and prepares it to be written to, starting at the end of the file. If the file does not exist, a new zero-length file is created. This value can be used only in tandem with the FileAccess.Write enumeration value; otherwise, an ArgumentException is thrown.
Create Creates a new file. If the specified file exists, it is truncated. If you do not wish to lose data, consider employing the CreateNew enumeration value instead. This value can be used only in tandem with the FileAccess.Write or FileAccess.ReadWrite enumeration values; otherwise, an ArgumentException is thrown.
CreateNew Creates a new file. An IOException is thrown if the file already exists. This prevents accidental data loss. This value can be used only in tandem with the FileAccess.Write or FileAccess.ReadWrite enumeration values; otherwise, an ArgumentException is thrown.
Open Opens an existing file. A FileNotFoundException is thrown if the file does not exist. Use OpenOrCreate if it is possible that the file might not already exist.
OpenOrCreate Opens a file if it exists or creates a new one if it does not exist. Consider using Open if you expect the file to always exist before it is opened. An ArgumentException is not thrown if this enumeration value is used in tandem with the FileAccess.Read enumeration value.
Truncate Opens an existing file and deletes all information in that file. A FileNotFoundException is thrown if the file does not exist. This value can be used in tandem with the FileAccess.Write or FileAccess.ReadWrite enumeration values; otherwise, an ArgumentException is thrown.

FileAccess enumeration values

Value Name Definition
Read Allows data only to be read from a file.
ReadWrite Allows data to be read from and written to a file. Same as FileAccess.Read | FileAccess.Write.
Write Allows data only to be written to a file.

FileShare enumeration values

Value Name Definition
Inheritable Not supported in Win32.
None The file cannot be accessed (read from or written to) or deleted by this or any other process.
Read The file cannot be written to or deleted by this or any other process. It can be read from.
Write The file cannot be read from or deleted by this or any other process. It can be written to.
Read The file can be read from or written to by this or any other process. The file still cannot be deleted while it is being shared in this mode. Same as using FileShare.Read | FileShare.Write.

In addition to these enumerations that define how a file is opened, the FileStream constructor allows you to define whether this stream will be opened in a synchronous or asynchronous manner. This is the only class?f the ones discussed in this article that allows a file to be opened in an asynchronous manner.

The FileStream class also has methods for seeking to a point within a file stream, as well as locking or unlocking a portion or an entire file; locking will prevent other processes or threads from modifying the file. The other stream types discussed in this article do not have the ability to lock or unlock portions or an entire file. This locking/unlocking functionality cannot even be accessed through the BaseStream property of any of these types. Seeking within a file can be done directly using the BinaryReader or BinaryWriter classes. The StreamReader and StreamWriter classes cannot directly access the seek functionality. However, by using the BaseStream property of either the StreamReader or StreamWriter classes, the base stream’s seek functionality can be used.

FileStreams can also be created using the static methods of the File class. The table below shows these methods,
along with their equivalent FileStream object constructor parameters.
Static methods of the File class and their equivalent FileStream constructor calls

Static methods in File class Equivalent FileStream constructor call
FileStream fileStream =
File.Create("File.txt");
FileStream fileStream = new FileStream("File.txt",
FileMode.Create, FileAccess.ReadWrite, FileShare.None);
FileStream fileStream =
File.Open("File.txt");
FileStream fileStream = new FileStream("File.txt");
FileStream fileStream =
File.OpenRead("File.txt");
FileStream fileStream = new FileStream("File.txt",
FileMode.Open, FileAccess.Read, FileShare.Read);
FileStream fileStream =
File.OpenWrite("File.txt");
FileStream fileStream = new FileStream("File.txt",
FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);

The File.Open method is overloaded to accept FileMode, FileAccess, and
FileShare enumeration values. The FileStream constructor is also
overloaded to accept these same parameters. Therefore, to make an equivalent FileStream constructor for the File.Open method, we need to use the same parameters for each of these three enumeration values in both parameter lists.

The File class has a complementary class called FileInfo that contains similar methods, but these methods are instance, not static, methods. Table below shows the FileInfo methods, which are similar to the File static methods, along with their equivalent FileStream object constructor parameters.

Instance methods of the FileInfo class and equivalent FileStream constructor calls

Instance methods in FileInfo class Equivalent FileStream constructor call
FileInfo fileInfo =
new FileInfo("File.txt");

FileStream fileStream =
fileInfo.Create();
FileStream fileStream = new FileStream("File.txt",
FileMode.Create, FileAccess.ReadWrite, FileShare.None);
FileInfo fileInfo =
new FileInfo("File.txt");

FileStream fileStream =
fileInfo.Open(FileMode.Open);
FileStream fileStream = new FileStream("File.txt");
FileInfo fileInfo =
new FileInfo("File.txt");

FileStream fileStream =
fileInfo.OpenRead();
FileStream fileStream = new FileStream("File.txt",
FileMode.Open, FileAccess.Read, FileShare.Read);
FileInfo fileInfo =
new FileInfo("File.txt");

FileStream fileStream =
fileInfo.OpenWrite();
FileStream fileStream = new FileStream("File.txt",
FileMode.OpenOrCreate, FileAccess.Write, FileShare.
None);

The FileInfo.Open instance method is overloaded to accept FileMode,
FileAccess, and FileShare enumeration values. These values should be
matched in the FileStream constructor parameter list.

The StreamReader and StreamWriter objects can be created using their
overloaded constructors. These overloaded constructors accept as parameters either a file path and name or a
FileStream object. Therefore, we can use any of the previously mentioned ways of creating a
FileStream object in the construction of either a StreamReader or
StreamWriter object.

In addition, we can use three of the static methods in the File class or three of the instance
methods in the FileInfo class to create a StreamReader or
StreamWriter object. Table below describes the static methods of the File
class used to create StreamReader and StreamWriter objects and
their equivalent StreamReader and StreamWriter object constructor
parameters.

Static methods of the File class and their equivalent StreamReader/StreamWriter constructor calls

Static methods in File class Equivalent StreamReader/StreamWriter constructor calls
StreamReader streamReader =
File.OpenText("File.txt");
StreamReader streamReader = new StreamReader("File.
txt");
StreamWriter streamWriter =
File.AppendText("File.txt");
StreamWriter streamWriter = new StreamWriter("File.
txt", true);
StreamWriter streamWriter =
File.CreateText("File.txt");
StreamWriter streamWriter = new StreamWriter("File.
txt", false);

Table below describes the instance methods of the FileInfo class used to create StreamReader and StreamWriter object and their equivalent StreamReader and StreamWriter object constructor parameters.

Instance methods of the FileInfo class and their equivalent StreamReader/StreamWriter constructor calls

Instance methods in FileInfo class Equivalent StreamReader/StreamWriter constructor calls
FileInfo fileInfo =
new FileInfo("File.txt");

StreamReader streamReader =
fileInfo.OpenText();
StreamReader streamReader = new StreamReader("File.txt");
FileInfo fileInfo =
new FileInfo("File.txt");

StreamWriter streamWriter =
fileInfo.AppendText();
StreamWriter streamWriter = new StreamWriter("File.txt",
true);
FileInfo fileInfo =
new FileInfo("File.txt");

StreamWriter streamWriter =
fileInfo.AppendText();
StreamWriter streamWriter = new StreamWriter("File.txt",
false);

The methods of the File and FileInfo classes do not return BinaryReader and BinaryWriter classes; therefore, we rely on their constructors to create these types of objects. The overloaded BinaryReader and BinaryWriter class constructors accept only a Stream object; they do not accept a filename.

To create a BinaryReader or BinaryWriter object, we first need to create a StreamM type object. Since Stream is an abstract class, we need to create one of its derived classes, such as the FileStream class. Any of the prior ways of creating a FileStream object may be employed as a parameter in the constructor of either a BinaryReader or BinaryWriter. The following code creates both a BinaryReader and a BinaryWriter object from a single FileStream object:

fileStream = File.Create("filename.file");
BinaryWriter binaryWriter1 = new BinaryWriter(fileStream);
BinaryReader binaryReader1 = new BinaryReader(fileStream);

There are many different ways of combining the techniques discussed in this article to create and open files. For example, if you require file locking and/or asynchronous file processing, you will need a FileStream object. If you are
dealing with text streams in memory and on disk, perhaps the StreamReader and StreamWriter might be a better choice. Finally, if you are dealing with binary data or mixed binary and text data in different encodings, you should consider BinaryReader and BinaryWriter.

Here are a few examples of using the various built-in streams:

// create a temp file to work with
string tempFile = Path.GetTempFileName();

// FileStream
FileStream fileStream = null;
try
{
    // open the file
    fileStream = File.Open(tempFile, FileMode.Append);

    string text = "Hello World ";
    byte[] bytes = Encoding.ASCII.GetBytes(text.ToCharArray());

    // write to the file
    fileStream.Write(bytes, 0, bytes.Length);
}
finally
{
    //make sure the file is closed if it was opened
    if (fileStream != null)
        fileStream.Close();
}

// StreamReader
StreamReader streamReader = null;
try
{
    streamReader = new StreamReader(tempFile);
    char[] chars = new char[64];
    // read a block of characters
    streamReader.Read(chars, 0, 64);
    string charsFound = new string(chars);
    Console.WriteLine("Chars in stream {0}", charsFound);
}
finally
{
    if (streamReader != null)
        streamReader.Close();
}

// StreamWriter
StreamWriter streamWriter = null;
try
{
    // open for append
    streamWriter = new StreamWriter(tempFile, true);
    // append some text
    streamWriter.WriteLine(", It''s the StreamWriter!");
}
finally
{
    if (streamWriter != null)
        streamWriter.Close();
}

// BinaryWriter
BinaryWriter binaryWriter = null;
long pos = 0;
int twentyFive = 25;
try
{
    // start up the binary writer with the base stream from the streamwriter
    // since it is open
    binaryWriter = new BinaryWriter(streamWriter.BaseStream);
    // move to end
    pos = binaryWriter.Seek(0, SeekOrigin.End);
    // write out 25
    binaryWriter.Write(twentyFive);
}
finally
{
    // close up
    if (binaryWriter != null)
        binaryWriter.Close();
}

// BinaryReader
StreamReader streamReader2 = null;
BinaryReader binaryReader = null;
try
{
    // open a new reader
    streamReader2 = new StreamReader(tempFile);
    binaryReader = new BinaryReader(streamReader2.BaseStream);

    // advance the stream to the number we stored
    for (long i=0; i
int num = binaryReader.ReadInt32();
    // is this the same number...?
    if (num == twentyFive)
        Console.WriteLine("Successfully read 25 back from stream");
    else
        Console.WriteLine("Failed to successfully read 25 back from stream");
}
finally
{
    // close up
    if (binaryReader != null)
        binaryReader.Close();
    // close stream
    if (streamReader2 != null)
        streamReader2.Close();
}

Popularity: 2% [?]