private FileStream OpenSource() { var stream = Source.Open(FileMode.Open, FileAccess.Read, FileShare.Read); if (Destination.Exists && Options.HasFlag(FileCopyOptions.Restartable)) { stream.Seek(Destination.Length - BufferSize, SeekOrigin.Begin); } return(stream); }
private FileStream OpenDestination() { if (!Destination.Exists || !Options.HasFlag(FileCopyOptions.Restartable)) { return(Destination.Open(FileMode.Create, FileAccess.Write, FileShare.None)); } var stream = Destination.Open(FileMode.Open, FileAccess.Write, FileShare.None); stream.Seek(BufferSize, SeekOrigin.End); return(stream); }
public async Task CopyAsync(CancellationToken cancellation = default) { if (Options.HasFlag(FileCopyOptions.VerifyFileHash) && HashAlgorithm == default) { throw new Exception($"The {FileCopyOptions.VerifyFileHash} bit flag was set, but no hashing algorithm was specified."); } stopwatch.Start(); OnStarted(this, new FileCopyStartedEventArgs2(Source, Destination)); try { using (var freader = OpenSource()) using (var fwriter = OpenDestination()) { if (freader.Position != fwriter.Position) { freader.Position = fwriter.Position; } var inputBuffer = new byte[BufferSize]; var bytesWritten = 0; var tries = 0; while (true) { try { int bytesRead; while (0 != (bytesRead = await freader.ReadAsync(inputBuffer, 0, inputBuffer.Length, cancellation)) && !cancellation.IsCancellationRequested) { cancellation.ThrowIfCancellationRequested(); bytesWritten += await CopyBytesAsync(inputBuffer, bytesRead, fwriter); if (Options.HasFlag(FileCopyOptions.VerifyFileHash)) { HashAlgorithm.TransformBlock(inputBuffer, 0, bytesRead, inputBuffer, 0); OnChunkHashed(this, new FileHashProgressEventArgs(Source, new FileHashProgressData(Source.Length, bytesRead, sourceHash.Count, stopwatch.Elapsed))); } OnChunkTransferred(this, new FileTransferProgressEventArgs(Source, Destination, new FileTransferProgressData(Source.Length, bytesRead, bytesWritten, stopwatch.Elapsed))); } if (Options.HasFlag(FileCopyOptions.VerifyFileHash)) { HashAlgorithm.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length); sourceHash = HashAlgorithm.Hash.ToList(); } break; } catch (Exception e) { if (e is OperationCanceledException) { throw; } if (!RetrySettings.Retry || tries >= RetrySettings.RetryCount) { throw; } OnRetryStarted(this, new FileCopyRetryStartedEventArgs(tries++, RetrySettings.RetryInterval, e)); } } } cancellation.ThrowIfCancellationRequested(); if (Options.HasFlag(FileCopyOptions.VerifyFileHash)) { stopwatch.Reset(); Destination.Refresh(); EnsureChecksumsMatch(cancellation); } } catch (OperationCanceledException) { if (!Options.HasFlag(FileCopyOptions.Restartable)) { Destination.Delete(); } throw; } if (Options.HasFlag(FileCopyOptions.DeleteSourceOnSuccessfulCopy)) { Source.Delete(); } OnCompleted(this, EventArgs.Empty); }