Conflicts and errors
Copy, Move, CopyTo and MoveTo transfer whole trees, so two questions have to be answered before they run: what happens when the destination already exists, and what happens when one item in the middle fails. Each method takes an overload for both.
Conflicts
Section titled “Conflicts”The shortest form takes a flag. false is the default, so a call that omits it fails on an existing destination:
sourceFile.Copy(destinationFile, overwrite: true);FileSystemConflictResolveMode gives the remaining answers:
| Mode | Result |
|---|---|
Skip | The item is left as it is and the transfer continues. |
Overwrite | The destination is replaced. |
MergeDirectories | The two directories are merged instead of one replacing the other. |
ChangeSourceName | The transferred item takes the next free name at the destination, so the existing one survives. |
Error | The operation stops and throws. |
sourceDirectory.Copy(destinationDirectory, FileSystemConflictResolveMode.MergeDirectories);A whole tree rarely wants one answer for every item. FileSystemConflictResolveDelegate is asked per conflict and receives both sides:
sourceDirectory.Copy(destinationDirectory, (source, destination) => source is FileLink file && file.ModifyTime > ((FileLink)destination).ModifyTime ? FileSystemConflictResolveMode.Overwrite : FileSystemConflictResolveMode.Skip);Errors
Section titled “Errors”Without an exception resolver, the first failure ends the transfer and the exception reaches the caller. Half of a directory may already have been copied.
FileSystemExceptionResolveDelegate is the last parameter of every Copy and Move overload. It receives the failing pair, the exception and the attempt number, and decides what happens next:
| Mode | Result |
|---|---|
Skip | The failed item is left unprocessed and the transfer continues with the next one. |
Retry | The failed operation is attempted again. |
Error | The operation stops and rethrows to the caller. |
sourceDirectory.Copy(destinationDirectory, overwrite: true, (source, destination, exception, attempt) => exception is IOException && attempt < 3 ? FileSystemExceptionResolveMode.Retry : FileSystemExceptionResolveMode.Skip);The attempt counter is what keeps Retry from looping. A resolver that returns Retry unconditionally never gives up.
Asynchronous transfers
Section titled “Asynchronous transfers”CopyAsync, MoveAsync, CopyToAsync and MoveToAsync take the same parameters in the same positions. The resolvers stay synchronous, because they only choose a mode.
await sourceDirectory.CopyAsync(destinationDirectory, FileSystemConflictResolveMode.Skip);