The .NET Framework uses streams to send data to a variety of different medias. For example, the most common use is to send data to a file on the
file system. You can do this using several different Stream variants, such as TextWriter or BinaryWriter. The most basic of those is the
StreamWriter class. Using StreamWriter, you can specify a filename in the constructor, and then use the StreamWriter.Write method to save
data to that file. If you need to read data from that file later, you would use the StreamReader class.
You can also layer other classes on top of StreamWriter. If you want to write a compressed file, you would create an instance of the
GZipStream class. Then, when you create your StreamWriter class, you provide that GZipStream instance as part of the StreamWriter constructor.
Then, anytime you call StreamWriter.Write, that data is funneled through the GZipStream instance. GZipStream compresses the data
using a type of compression called GZip compression. When you need to read the data back later, you can’t just use an ordinary
StreamWriter, or the data will come back as gibberish. So, you need to do exactly the same thing in reverse—you create a GZipStream
instance set to decompress the data, and then create a StreamReader instance using your GZipStream instance. Then, you’ll be able to read
directly from the compressed file. The .NET Framework actually provides two
different compression methods for writing compressed files. The one most people use is GZip, that I just discussed. It’s a more effective
compression method than the Deflate compression method. They’re just different compression methods; they accomplish the
same thing. GZip is more common; it’s even built into the file system. Deflate is a little less common and a little less efficient. So, either one
will compress a file, but the compressed file will probably be a little smaller if you use GZip.
Now, the beauty of using streams is you can use a variety of different media, not just the file system. In the .NET Framework, you probably
won’t write to the file system unless you need to access the file in a different application. Instead, you should use Isolated Storage. Isolated Storage
is stored on the file system, so it is permanent, and you can close your application and re-launch your application and the data will still be there.
Isolated storage is, in fact, a file on the file system. But, the .NET Framework treats it as its own entity. So, an application can write to Isolated
Storage and read it back almost as if it were part of the file system, but it has some benefits that writing directly to the file system does not provide.
First, Isolated Storage is protected by the .NET Framework. Different users cannot access Isolated Storage. Different assemblies cannot
access another assembly's isolated storage. Perhaps most importantly, Isolated Storage works with the security principal of least privilege
because it takes fewer .NET Framework privileges to Isolated Storage than it does to write directly to the file system.. So, if you are writing a
file that will only be read back by your assembly and from the same user, you should always write to Isolated Storage instead of the file system.
When you use Isolated Storage you can protect it in two different ways. You can specify the user domain, which means only that assembly run by
that user can access files in Isolated Storage. Or, you can specify protection for the application domain. If you specify application domain, only
other assemblies running in the same application domain can access the isolated storage. Application domains really only become
important when you’re writing multi-threaded applications or applications that spawn other assemblies. So, at this point, you probably won’t
use it. But, we will discuss application domains in later modules.
Another way to use StreamWriter is to write through the MemoryStream class. Just as we discussed when using GZipStream or
DeflateStream, you will create an instance of MemoryStream, and then specify the instance when you create your StreamWriter instance.
Then, when you call StreamWriter.Write to save data, it will be processed by the MemoryStream class. MemoryStream completely bypasses the
file system and stores the data in the computer’s RAM, in the memory itself. So, it’s not persistent. If you save data to a MemoryStream instance
and the user closes the application, the data’s gone. If the computer shuts down, the data’s gone. It’s stored in the computer’s memory, so
it’s only persistent while the application and the computer are running. For that reason, you wouldn’t normally use MemoryStream unless
you need to prepare a file to be written to the file system later. For example, if you need to gradually create a file over the course of five
minutes—perhaps you’re querying a database server and processing data and then outputting it to a file, you might write that data to a
MemoryStream, and then once the data had been processed, you might copy the data to the file system using another instance of StreamWriter.
That might be useful when multiple users might be accessing the same file, or when you need to minimize the number of writes that you make to
a particular file. So, think of a MemoryStream as a way to pre-write data to a file. But, remember that it’s not backed by the file system, so if your
application is interrupted, it’s gone forever.