Specifically, a FileStream exists to perform reads and writes to the file system. Most streams are pretty low-level in their usage, and deal with data as bytes. A StreamWriter is a wrapper for a Stream that simplifies using that stream to output plain text.
The StreamWriter class in C# is used for writing characters to a stream. It uses the TextWriter class as a base class and provides the overload methods for writing data into a file. The StreamWriter is mainly used for writing multiple characters of data into a file.
The StreamReader and StreamWriter classes are used for reading from and writing data to text files. These classes inherit from the abstract base class Stream, which supports reading and writing bytes into a file stream.
StreamWriter. Write() method is responsible for writing text to a stream. StreamWriter class is inherited from TextWriter class that provides methods to write an object to a string, write strings to a file, or to serialize XML. StreamWriter is defined in the System.IO namespace.
Streams handle bytes, Writers handle characters.
Bytes != characters. A character may take more than one byte to represent. The mapping from characters to bytes is called an encoding.
A FileStream
refers to the bytes being written to a file, similar to how a MemoryStream
refers to the bytes written to an in-memory buffer. In order to write characters to a stream, you'd need to convert them to a string of bytes. That's where a StreamWriter
comes in to play. It takes a sequence of characters and an encoding, and turns it into a sequence of bytes.
A TextWriter
is an interface (well, abstract base class) that all of the Writers must adhere to. It has all operations based on characters. The equivalent for bytes is the Stream
abstract base class.
Things also go in the opposite direction. There is a TextReader
abstract base class, describing how to read characters from somewhere, and a StreamReader
, which allows you to read characters from a byte-oriented stream supplying an encoding - but this time used in reverse, to aggregate any multi-byte sequences into single characters where appropriate.
A Stream
can be used for both reading and writing, since bytes are the lowest-level items used in I/O operations.
I've always found the best thing to do is just look at what methods they provide and how you can build them. This is almost always the main, if not only, thing I care about when using an API. How do I build it and what can it do?
You can't instantiate a TextWriter. It's abstract. That tells me the only real purpose it serves is, well, abstraction. If you write a function that takes any kind of writer as an argument, there's a good chance you should just take TextWriter to be more versatile.
A StreamWriter you can instantiate, and it does just what it says, it writes to streams. That means it will need a stream to get any real writing done. Once you have that stream though, you can do all sorts of neat things like writing a whole line at once instead of having to deal with individual characters (or rather bytes) like you would directly on the stream.
So basically, you get a stream so you can feed it to a StreamWriter (or Reader). If you're writing text, you probably don't want to work directly with a stream, no more than you want to work with a character array instead of a string.
FileStreams can conveniently be instantiated directly from the File and FileInfo classes, and in my usage, this is how they're usually instantiated. Get a file (I like to use FileInfo) and call OpenWrite(). Pass it along to a StreamWriter (which is just a type of TextWriter) and you're on your way.
To generalize: When you want to figure out a class, try looking at how you instantiate it and what it can do. This usually clears up a lot.
There's an obvious difference between a "Stream" and a "Writer/Reader".
A stream is a byte level representation, and is really an abstract concept that can be implemented in a variety of ways. For example, you have a FileStream and a MemoryStream. Both those are streams of bytes, but they are stored differently.
Writers and Readers give you a way to process streams, adding and extracting data from them.
For your particular examples, TextWriter is an abstract class that writes characters to a stream sequentially. It has several implementations (StreamWriter, StringWriter) that do are useful in different contexts. You would use whichever makes sense at the time. For several APIs however, all that is needed is a TextWriter, or something to call "Write" or "WriteLine" on. It isn't a concern of those APIs if your writer is used to put stuff into a string, some arbitrary memory, or a file.
The FileStream class manages getting a handle to a file and opening it for reading or writing and other filesystem functions. BinaryWriter writes binary data to a stream and StreamWriter writes character data to a stream. They both can use a FileStream object to write binary or character data to files.
TextWriter is the base class that StreamWriter inherits from. A TextWriter is intended to take a type and output a string using its Write method. StreamWriter's implementation of the TextWriter.Write method writes a string, or character data, to a stream. BinaryWriter does not inherit TextWriter because it does not write character data to a stream.
Stream
is an abstract base class that represents a series of bytes.
MemoryStream
is a stream of bytes held in memory, backed by an Array.
FileStream
is a stream of bytes in a file, usually backed by a file handle somewhere on disk.
Text characters are themselves composed of bytes, and a single character can be multiple bytes, depending on the encoding. There are some standard classes that read and write text to different sources using a specific encoding.
TextWriter
is an abstract base class for writing text characters to a destination.
StreamWriter
writes text characters (converted to bytes) to a stream of bytes.StringWriter
writes text characters to a string (via a StringBuilder).TextReader
is an abstract base class for reading text characters from a source.
StreamReader
reads text characters (converted from bytes) from a stream of bytes.StringReader
reads text characters from a string.Stream
, TextWriter
, TextReader
are all abstract base classes so they are never used directly but through an implementation like the ones described above. However you will see the base classes in method definitions so that different implementations can be used, including your own custom ones if necessary. Abstract classes are similar to interfaces but can actually define the logic for methods, which can be reused without every implementation repeating the same basic code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With