views:

1336

answers:

4

Let me first apologize if this question could sound perhaps sort of amateurish for the seasoned programmers among you, the thing is I've been having many arguments about this at work so I really want to get this straight and that's basically why I'm relying on the stackoverflow community to get this settled once and for all :)

So, on the one hand according to MSDN, we have:

TextWriter Class

Represents a writer that can write a sequential series of characters. This class is abstract.

FileStream Class

Exposes a Stream around a file, supporting both synchronous and asynchronous read and write operations.

StreamWriter Class

Implements a TextWriter for writing characters to a stream in a particular encoding.

On the other hand it's evident they all belong to System.IO but given that MSDN examples kind of mix some of them, I'm still not reaching the much desired a-ha moment.

Any comment would be more than appreciated, thanks much in advance!

+11  A: 

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. In order to write characters to that 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, base abstract class) that all of the Writers must adhere to. It has all operations based on characters. The equivalent for bytes is the Stream interface.

Things also go in the opposite direction. There is a TextReader interface (again, abstract 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.

The Stream interface can be used for both reading and writing, since bytes are the lowest-level items used in I/O operations.

lavinio
TextWriter is not an interface, it's an abstract base class.
scottm
Thanks much for the comment lavinio! In this particular case I'm trying to solve I have to deal with BLOBs, namely reading a database field then writing to disk and visce-versa, so I guess Streams are the way to go?
Nano Taboada
Pulling from a file, to a BLOB is probably a binary operation, so yes, Streams are the way to go. If there are CLOBs around, then you might want to use the Reader/Writer classes.
lavinio
+1  A: 

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.

scottm
Thanks for the comment scotty2012!
Nano Taboada
+2  A: 

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.

Nader Shirazie
Thanks much nader!
Nano Taboada
+2  A: 

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.

Daniel Straight
Thanks MUCH for your advice Daniel, it's been really informative!
Nano Taboada