public override void Write(byte[] buffer, int offset, int count)
{
if (buffer == null)
throw new ArgumentNullException("buffer");
if (offset < 0)
throw new ArgumentOutOfRangeException("offset");
if (count < 0)
throw new ArgumentOutOfRangeException("count");
if ((buffer.Length - offset) < count)
throw new ArgumentException("Invalid array range.");
// Lock down the file stream while we do this.
lock (_lock)
{
CheckSessionIsOpen();
// Setup this object for writing.
SetupWrite();
// Write data to the file stream.
while (count > 0)
{
// Determine how many bytes we can write to the buffer.
var tempLen = _writeBufferSize - _bufferPosition;
if (tempLen <= 0)
{
// flush write buffer, and mark it empty
FlushWriteBuffer();
// we can now write or buffer the full buffer size
tempLen = _writeBufferSize;
}
// limit the number of bytes to write to the actual number of bytes requested
if (tempLen > count)
{
tempLen = count;
}
// Can we short-cut the internal buffer?
if (_bufferPosition == 0 && tempLen == _writeBufferSize)
{
using (var wait = new AutoResetEvent(false))
{
_session.RequestWrite(_handle, _serverFilePosition, buffer, offset, tempLen, wait);
_serverFilePosition += (ulong) tempLen;
}
}
else
{
// No: copy the data to the write buffer first.
Buffer.BlockCopy(buffer, offset, _writeBuffer, _bufferPosition, tempLen);
_bufferPosition += tempLen;
}
// Advance the buffer and stream positions.
_position += tempLen;
offset += tempLen;
count -= tempLen;
}
// If the buffer is full, then do a speculative flush now,
// rather than waiting for the next call to this method.
if (_bufferPosition >= _writeBufferSize)
{
using (var wait = new AutoResetEvent(false))
{
_session.RequestWrite(_handle, _serverFilePosition, _writeBuffer, 0, _bufferPosition, wait);
_serverFilePosition += (ulong) _bufferPosition;
}
_bufferPosition = 0;
}
}
}