Recipe 11.20 Write to Multiple Output Files at One Time
Problem
Any output that
is written to one file must also be written to at least one other
file. Essentially, you want to end up with at least the original file
and the duplicate file.
Solution
Create a class called MultiWriter with the ability
to write to multiple files from a single
WriteLine call.
To create a set of files, just pass the file paths you would like to
use to the constructor like this:
// Create a list of three file names
string[] names = new string[3];
for (int i=0;i<3;i++)
{
names[i] = Path.GetTempFileName( );
}
MultiWriter multi = new MultiWriter(names);
Next, perform the writes and close the instance:
multi.WriteLine("First Line");
multi.WriteLine("Second Line");
multi.WriteLine("Third Line");
multi.Close( );
Here is
the implementation of the MultiWriter class:
class MultiWriter : IDisposable
{
FileStream[] _streams;
string [] _names;
int _streamCount = 0;
bool _disposed = false;
public MultiStream(string[] fileNames)
{
try
{
// copy the names
_names = (string[])fileNames.Clone( );
// set the number of streams
_streamCount = fileNames.Length;
// make the stream array
_streams = new FileStream[_streamCount];
for(int i = 0; i < _streams.Length; i++)
{
// create this filestream
_streams[i] = new FileStream(_names[i],
FileMode.Create,
FileAccess.ReadWrite,
FileShare.None);
}
}
catch(IOException ioe)
{
Console.WriteLine(ioe.ToString( ));
}
}
public void WriteLine(string text)
{
// add a newline
text += Environment.NewLine;
// get the bytes in unicode format...
byte[] bytes = Encoding.ASCII.GetBytes(text);
// roll over the streams
for(int i = 0; i < _streams.Length; i++)
{
// write the text
_streams[i].Write(bytes,0,bytes.Length);
}
}
public void Close( )
{
Dispose( );
}
public void Dispose( )
{
try
{
// only close out once
if(_disposed == false)
{
// close each stream
for(int i=0;i<_streams.Length;i++)
{
_streams[i].Close( );
}
// prevent refinalizing
GC.SuppressFinalize(this);
// indicate we have done this already
_disposed = true;
}
}
catch(IOException ioe)
{
Console.WriteLine(ioe.ToString( ));
}
}
}
Discussion
MultiStream implements the
IDisposable interface, which helps the users
remember to close the files this will create. Ultimately, if the user
forgets to call Close (a thin wrapper around
Dispose for semantic convenience), the finalizer
(~MultiStream) will call
Dispose anyway and close the files when the
garbage collector finalizes the instance. Note that in the
Dispose method, we check to see whether the
instance has been disposed before; if not, we close the file streams
we created internally and call the
GC.SuppressFinalize method. This is an
optimization to keep the garbage collector from having to call our
finalizer and subsequently hold on to the object longer.
See Also
See the "FileStream Class,"
"GC Class," and
"IDisposable Interface" topics in
the MSDN documentation.
|