/// <summary> /// Creates and initializes a new asynchronous copy operation. /// </summary> /// <param name="src">The source stream.</param> /// <param name="dest">The destination stream.</param> /// <param name="state">An ExecutionState used to coordinate copy operation.</param> /// <param name="bufferManager">IBufferManager instance to use. May be null.</param> /// <param name="buffSize">Size of read and write buffers used to move data. Overrides the default buffer size of bufferManager.</param> /// <param name="calculateChecksum">A value indicating whether the checksums should be calculated.</param> /// <param name="streamCopyState">An object that represents the state for the current operation.</param> public AsyncStreamCopier(Stream src, Stream dest, ExecutionState <T> state, IBufferManager bufferManager, int?buffSize, ChecksumRequested calculateChecksum, StreamDescriptor streamCopyState) { this.src = src; this.dest = dest; this.state = state; this.bufferManager = bufferManager; this.buffSize = buffSize ?? (bufferManager != null ? bufferManager.GetDefaultBufferSize() : Constants.DefaultBufferSize); this.streamCopyState = streamCopyState; if (streamCopyState != null && calculateChecksum.HasAny && streamCopyState.ChecksumWrapper == null) { streamCopyState.ChecksumWrapper = new ChecksumWrapper(calculateChecksum.MD5, calculateChecksum.CRC64); } }
/// <summary> /// Creates and initializes a new asynchronous copy operation. /// </summary> /// <param name="src">The source stream.</param> /// <param name="dest">The destination stream.</param> /// <param name="state">An ExecutionState used to coordinate copy operation.</param> /// <param name="bufferManager">IBufferManager instance to use. May be null.</param> /// <param name="buffSize">Size of read and write buffers used to move data. Overrides the default buffer size of bufferManager.</param> /// <param name="calculateMd5">Boolean value indicating whether the MD-5 should be calculated.</param> /// <param name="streamCopyState">An object that represents the state for the current operation.</param> public AsyncStreamCopier(Stream src, Stream dest, ExecutionState <T> state, IBufferManager bufferManager, int?buffSize, bool calculateMd5, StreamDescriptor streamCopyState) { this.src = src; this.dest = dest; this.state = state; this.bufferManager = bufferManager; this.buffSize = buffSize ?? (bufferManager != null ? bufferManager.GetDefaultBufferSize() : Constants.DefaultBufferSize); this.streamCopyState = streamCopyState; if (streamCopyState != null && calculateMd5 && streamCopyState.Md5HashRef == null) { streamCopyState.Md5HashRef = new MD5Wrapper(); } }
internal static void WriteToSync <T>(this Stream stream, Stream toStream, long?copyLength, long?maxLength, bool calculateMd5, bool syncRead, ExecutionState <T> executionState, StreamDescriptor streamCopyState) { if (copyLength.HasValue && maxLength.HasValue) { throw new ArgumentException(SR.StreamLengthMismatch); } if (stream.CanSeek && maxLength.HasValue && stream.Length - stream.Position > maxLength) { throw new InvalidOperationException(SR.StreamLengthError); } if (stream.CanSeek && copyLength.HasValue && stream.Length - stream.Position < copyLength) { throw new ArgumentOutOfRangeException("copyLength", SR.StreamLengthShortError); } byte[] buffer = new byte[GetBufferSize(stream)]; if (streamCopyState != null && calculateMd5 && streamCopyState.Md5HashRef == null) { streamCopyState.Md5HashRef = new MD5Wrapper(); } RegisteredWaitHandle waitHandle = null; ManualResetEvent completedEvent = null; if (!syncRead && executionState.OperationExpiryTime.HasValue) { completedEvent = new ManualResetEvent(false); waitHandle = ThreadPool.RegisterWaitForSingleObject( completedEvent, StreamExtensions.MaximumCopyTimeCallback <T>, executionState, executionState.RemainingTimeout, true); } try { long?bytesRemaining = copyLength; int readCount; do { if (executionState.OperationExpiryTime.HasValue && DateTime.Now.CompareTo(executionState.OperationExpiryTime.Value) > 0) { throw Exceptions.GenerateTimeoutException(executionState.Cmd != null ? executionState.Cmd.CurrentResult : null, null); } // Determine how many bytes to read this time so that no more than copyLength bytes are read int bytesToRead = MinBytesToRead(bytesRemaining, buffer.Length); if (bytesToRead == 0) { break; } // Read synchronously or asynchronously readCount = syncRead ? stream.Read(buffer, 0, bytesToRead) : stream.EndRead(stream.BeginRead(buffer, 0, bytesToRead, null /* Callback */, null /* State */)); // Decrement bytes to write from bytes read if (bytesRemaining.HasValue) { bytesRemaining -= readCount; } // Write if (readCount > 0) { toStream.Write(buffer, 0, readCount); // Update the StreamDescriptor after the bytes are successfully committed to the output stream if (streamCopyState != null) { streamCopyState.Length += readCount; if (maxLength.HasValue && streamCopyState.Length > maxLength.Value) { throw new InvalidOperationException(SR.StreamLengthError); } if (streamCopyState.Md5HashRef != null) { streamCopyState.Md5HashRef.UpdateHash(buffer, 0, readCount); } } } }while (readCount != 0); if (bytesRemaining.HasValue && bytesRemaining != 0) { throw new ArgumentOutOfRangeException("copyLength", SR.StreamLengthShortError); } } catch (Exception) { if (executionState.OperationExpiryTime.HasValue && DateTime.Now.CompareTo(executionState.OperationExpiryTime.Value) > 0) { throw Exceptions.GenerateTimeoutException(executionState.Cmd != null ? executionState.Cmd.CurrentResult : null, null); } else { throw; } } finally { if (waitHandle != null) { waitHandle.Unregister(null); } if (completedEvent != null) { completedEvent.Close(); } } if (streamCopyState != null && streamCopyState.Md5HashRef != null) { streamCopyState.Md5 = streamCopyState.Md5HashRef.ComputeHash(); streamCopyState.Md5HashRef = null; } }
internal static Task WriteToAsync <T>(this Stream stream, Stream toStream, IBufferManager bufferManager, long?copyLength, long?maxLength, bool calculateMd5, ExecutionState <T> executionState, StreamDescriptor streamCopyState, CancellationToken cancellationToken, Action <ExecutionState <T> > completed = null) { AsyncStreamCopier <T> copier = new AsyncStreamCopier <T>(stream, toStream, executionState, bufferManager, GetBufferSize(stream), calculateMd5, streamCopyState); return(copier.StartCopyStream(completed, copyLength, maxLength, cancellationToken)); }
/// <summary> /// Asynchronously reads the entire content of the stream and writes it to the given output stream. /// </summary> /// <param name="stream">The origin stream.</param> /// <param name="toStream">The destination stream.</param> /// <param name="bufferManager">IBufferManager instance to use. May be null.</param> /// <param name="copyLength">Number of bytes to copy from source stream to destination stream. Cannot be passed with a value for maxLength.</param> /// <param name="maxLength">Maximum length of the source stream. Cannot be passed with a value for copyLength.</param> /// <param name="calculateMd5">Bool value indicating whether the Md5 should be calculated.</param> /// <param name="executionState">An object that stores state of the operation.</param> /// <param name="streamCopyState">An object that represents the current state for the copy operation.</param> /// <param name="token">A CancellationToken to observe while waiting for the copy to complete.</param> /// <returns>The task object representing the asynchronous operation.</returns> internal static async Task WriteToAsync <T>(this Stream stream, Stream toStream, IBufferManager bufferManager, long?copyLength, long?maxLength, bool calculateMd5, ExecutionState <T> executionState, StreamDescriptor streamCopyState, CancellationToken token) { if (copyLength.HasValue && maxLength.HasValue) { throw new ArgumentException(SR.StreamLengthMismatch); } if (stream.CanSeek && maxLength.HasValue && stream.Length - stream.Position > maxLength) { throw new InvalidOperationException(SR.StreamLengthError); } if (stream.CanSeek && copyLength.HasValue && stream.Length - stream.Position < copyLength) { throw new ArgumentOutOfRangeException("copyLength", SR.StreamLengthShortError); } if (streamCopyState != null && calculateMd5 && streamCopyState.Md5HashRef == null) { streamCopyState.Md5HashRef = new MD5Wrapper(); } CancellationTokenSource cts = null; byte[] buffer = bufferManager != null?bufferManager.TakeBuffer(GetBufferSize(stream)) : new byte[GetBufferSize(stream)]; try { if (executionState.OperationExpiryTime.HasValue) { // Setup token for timeout cts = CancellationTokenSource.CreateLinkedTokenSource(token); cts.CancelAfter(executionState.RemainingTimeout); // Switch tokens token = cts.Token; } long?bytesRemaining = copyLength; int readCount; do { // Determine how many bytes to read this time so that no more than count bytes are read int bytesToRead = bytesRemaining.HasValue && bytesRemaining < buffer.Length ? (int)bytesRemaining : buffer.Length; if (bytesToRead == 0) { break; } readCount = await stream.ReadAsync(buffer, 0, bytesToRead, token).ConfigureAwait(false); if (bytesRemaining.HasValue) { bytesRemaining -= readCount; } if (readCount > 0) { await toStream.WriteAsync(buffer, 0, readCount, token).ConfigureAwait(false); // Update the StreamDescriptor after the bytes are successfully committed to the output stream if (streamCopyState != null) { streamCopyState.Length += readCount; if (maxLength.HasValue && streamCopyState.Length > maxLength.Value) { throw new InvalidOperationException(SR.StreamLengthError); } if (streamCopyState.Md5HashRef != null) { streamCopyState.Md5HashRef.UpdateHash(buffer, 0, readCount); } } } }while (readCount > 0); if (bytesRemaining.HasValue && bytesRemaining != 0) { throw new ArgumentOutOfRangeException("copyLength", SR.StreamLengthShortError); } } finally { if (cts != null) { cts.Dispose(); cts = null; } if (buffer != null && bufferManager != null) { bufferManager.ReturnBuffer(buffer); } } // Streams opened with AsStreamForWrite extension need to be flushed // to write all buffered data to the underlying Windows Runtime stream. await toStream.FlushAsync().ConfigureAwait(false); if (streamCopyState != null && streamCopyState.Md5HashRef != null) { streamCopyState.Md5 = streamCopyState.Md5HashRef.ComputeHash(); streamCopyState.Md5HashRef = null; } }