using System;
using System.IO;
namespace CGS
{
///
/// Wraps another stream and provides reporting for when bytes are read or written to the stream.
///
public class ProgressStream : Stream
{
#region Private Data Members
private Stream innerStream;
#endregion
#region Constructor
///
/// Creates a new ProgressStream supplying the stream for it to report on.
///
/// The underlying stream that will be reported on when bytes are read or written.
public ProgressStream(Stream streamToReportOn)
{
if (streamToReportOn != null)
{
this.innerStream = streamToReportOn;
}
else
{
throw new ArgumentNullException("streamToReportOn");
}
}
#endregion
#region Events
///
/// Raised when bytes are read from the stream.
///
public event ProgressStreamReportDelegate BytesRead;
///
/// Raised when bytes are written to the stream.
///
public event ProgressStreamReportDelegate BytesWritten;
///
/// Raised when bytes are either read or written to the stream.
///
public event ProgressStreamReportDelegate BytesMoved;
protected virtual void OnBytesRead(int bytesMoved)
{
if (BytesRead != null)
{
var args = new ProgressStreamReportEventArgs(bytesMoved, innerStream.Length, innerStream.Position, true);
BytesRead(this, args);
}
}
protected virtual void OnBytesWritten(int bytesMoved)
{
if (BytesWritten != null)
{
var args = new ProgressStreamReportEventArgs(bytesMoved, innerStream.Length, innerStream.Position, false);
BytesWritten(this, args);
}
}
protected virtual void OnBytesMoved(int bytesMoved, bool isRead)
{
if (BytesMoved != null)
{
var args = new ProgressStreamReportEventArgs(bytesMoved, innerStream.Length, innerStream.Position, isRead);
BytesMoved(this, args);
}
}
#endregion
#region Stream Members
public override bool CanRead
{
get { return innerStream.CanRead; }
}
public override bool CanSeek
{
get { return innerStream.CanSeek; }
}
public override bool CanWrite
{
get { return innerStream.CanWrite; }
}
public override void Flush()
{
innerStream.Flush();
}
public override long Length
{
get { return innerStream.Length; }
}
public override long Position
{
get
{
return innerStream.Position;
}
set
{
innerStream.Position = value;
}
}
public override int Read(byte[] buffer, int offset, int count)
{
var bytesRead = innerStream.Read(buffer, offset, count);
OnBytesRead(bytesRead);
OnBytesMoved(bytesRead, true);
return bytesRead;
}
public override long Seek(long offset, SeekOrigin origin)
{
return innerStream.Seek(offset, origin);
}
public override void SetLength(long value)
{
innerStream.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
innerStream.Write(buffer, offset, count);
OnBytesWritten(count);
OnBytesMoved(count, false);
}
public override void Close()
{
innerStream.Close();
base.Close();
}
#endregion
}
///
/// Contains the pertinent data for a ProgressStream Report event.
///
public class ProgressStreamReportEventArgs : EventArgs
{
///
/// The number of bytes that were read/written to/from the stream.
///
public int BytesMoved { get; private set; }
///
/// The total length of the stream in bytes.
///
public long StreamLength { get; private set; }
///
/// The current position in the stream.
///
public long StreamPosition { get; private set; }
///
/// True if the bytes were read from the stream, false if they were written.
///
public bool WasRead { get; private set; }
///
/// Default constructor for ProgressStreamReportEventArgs.
///
public ProgressStreamReportEventArgs()
: base() { }
///
/// Creates a new ProgressStreamReportEventArgs initializing its members.
///
/// The number of bytes that were read/written to/from the stream.
/// The total length of the stream in bytes.
/// The current position in the stream.
/// True if the bytes were read from the stream, false if they were written.
public ProgressStreamReportEventArgs(int bytesMoved, long streamLength, long streamPosition, bool wasRead)
:this()
{
this.BytesMoved = bytesMoved;
this.StreamLength = streamLength;
this.StreamPosition = streamPosition;
this.WasRead = WasRead;
}
}
///
/// The delegate for handling a ProgressStream Report event.
///
/// The object that raised the event, should be a ProgressStream.
/// The arguments raised with the event.
public delegate void ProgressStreamReportDelegate(object sender, ProgressStreamReportEventArgs args);
}