15. Streams and I/O || C# 10 Flashcards
Can you name 3 concepts on which the .NET stream architecture centers?
- Backing stores
- decorators
- adapters
What is a ‘backing store’?
A backing store is the endpoint that makes input and output useful, such as a file or network connection. Precisely, it is either or both of the following:
- A source from which bytes can be sequentially read;
- A destination to which bytes can be sequentially written;
What is a Stream?
A stream exposes a standard set of methods for reading, writing and positioning. Unlike an array, for which all the backing data exists in memory at once, a stream deals with data serially - either one byte at a time or in blocks of manageable size. Hence, a stream can use a small, fixed amount of memory regardless of the size of its backing store.
The abstract Stream class is the base for all streams. It defines methods and properties for three fundamental operations: reading, writing and seeking;
How can we categorize streams?
Streams fall into two categories:
- Backing store streams: These are hardwired to a particular type of backing store, such as
FileStream
orNetworkStream
; - Decorator streams: These feed off another stream, transforming the data in some way, such as
DeflateStream
orCryptoStream
;
To summarize, backing store streams provide the raw data, decorator streams provide transparent binary transformations such as encryption
Can you name the benefits of Decorator streams?
Decorator streams have the following architectural benefits:
1. They liberate backing store streams from needing to implement such features as compression and encryption themselves;
2. Streams don’t suffer a change of interface when decorated;
3. You connect decorators at runtime;
4. You can chain decorators together (e.g. a compressor followed by an encryptor);
What is an adaptor in streams as a topic?
If we consider that backing stores and decorator streams deal exclusively in bytes, when applications often work at higher level, such as text or XML, we need some sort of translation between the types.
Adaptors bridge this gap by wrapping a stream in a class with specialized methods typed to a particular format. For example, a text reader exposes ReadLine
method, an XML writer exposes a WriteAttributes
method.
An adaptor wraps a stream, just like a decorator. Unlike a decorator, however, an adapter is not itself a stream; it typically hides the byte-oriented methods completely.
Adapters offer typed methods for dealing with higher level types such as strings and XML.
Explain how the Read method in Streams work
Read
receives a block of data from the stream into an array. It returns the number of bytes received, which is always either less than or equal to the count argument. If it’s less than count, it means that either the end of the stream has been reached or the stream is giving you the data in smaller chunks (as is often the case with network streams). In either case, the balance of bytes in the array will remain unwritten, their previous values preserved.
With Read
you can be certain you’ve reached the end of the stream only when the method returns 0
What does the Seek
method allows to do?
The Seek
method allows you to move relative to the current position or the end of the stream.
With nonseekable stream (such as an encryption stream) the only way to determine its length is to read it completely through. Furthermore if you need to reread a previous section, you must close the stream and start fresh with a new one.
Describe disposal semantics of the stream
In general streams follow sandard disposal semantics:
-
Dispose
andClose
are identical in function; - Disposing or closing a stream repeatedly causes no error.
Closing a decorator stream closes both the decorator and its backing store stream. With a chain of decorators, closing the outermost decorator closes the whole lot.
Are streams thread-safe?
As a rule, streams are not thread-safe, meaning two threads cannot concurrently read or write to the same stream without possible error.
As a workaround there is a Synchronized
method, that returns a thread-safe wrapper. The wrapper works by obtaining an exclusive lock around each read, write or seek, ensuring that only one thread can perform such an operation at a time.
FileStream class, besides others, has two methods - OpenWrite
and Create
. Both of them write content into the file, but what are the differences?
The differences shows up when we try to write something into a file that already have some content written in it. Create
method truncates any existing content while OpenWrite
leaves existing content intact with the stream positioned at zero. If you write fewer bytes than were previously in the file, OpenWrite
leaves you with a mixture of old and new content.
What’s the difference between ReadLines and ReadAllLines?
They do the same thing except ReadLines returns lazily evaluated IEnumerable<string>
. This is more efficient because it doesnt load the entire file into memory at once.
What is a MemoryStream?
MemoryStream uses an array as a backing store. This partly defeats the purpose of having a stream because the entire backing store must reside in memory at once. MemoryStream is still usefull when you need random access to a nonseekable stream.
You can conver MemoryStream into byte array by calling ToArray. The GetBuffer method does the same job more efficiently by returning a direct reference to the underlying storage array.
Also fun fact that calling Flush on MemoryStream does absolutely nothing :)
What is a PipeStream?
PipeStream provides a simple means by which one process can communicate with another through the operating system’s protocol. There are two kinds of pipe:
1. Anonymous pipe (faster):
Allows one-way communication between a parent and child process on the same computer;
2. Named pipe (more flexible):
Allows two-way communication between arbitrary processes on the same computer or different computers across a network.
A pipe is good for interprocess communication on a single computerL it doesn’t rely on a network transport, which means no network protocol overhead, and it has no issues with firewalls.
A pipe is good for interprocess comunication on a single computer: it doesn’t rely on a network transport, which means no network protocol overhead, and it has no issues with firewalls.
Pipes are stream based, so one process waits to receive a series of bytes while another process sends them.
Define PipeStream class
PipeStream is an abstract class with four concrete subtypes. Two are used for anonymous pipes and other two for named pipes.
Named pipes are simpler to use.