Skip to content

Instantly share code, notes, and snippets.

@emoacht
Created January 28, 2015 13:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save emoacht/cc18a531a35dcec34b00 to your computer and use it in GitHub Desktop.
Save emoacht/cc18a531a35dcec34b00 to your computer and use it in GitHub Desktop.
Copy a file with Stream.
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
public class StreamCopy
{
private const int bufferSize = 1024 * 1024; // 1MiB
private static readonly TimeSpan throttleTime = TimeSpan.FromMilliseconds(10);
public static async Task CopyFileAsync(string sourceFilePath, string destinationFilePath, CancellationToken cancellationToken)
{
using (var ss = new FileStream(sourceFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var ds = new FileStream(destinationFilePath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
{
await ss.CopyToAsync(ds, bufferSize, cancellationToken).ConfigureAwait(false);
}
}
public static async Task CopyFile2Async(string sourceFilePath, string destinationFilePath, CancellationToken cancellationToken)
{
using (var ss = new FileStream(sourceFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var ds = new FileStream(destinationFilePath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
{
var buffer = new byte[bufferSize];
while (ds.Position < ss.Length)
{
var readCount = await ss.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false);
await ds.WriteAsync(buffer, 0, readCount, cancellationToken).ConfigureAwait(false);
Debug.WriteLine("write {0:f3}%", (double)ds.Position / (double)ss.Length);
}
}
}
public static async Task CopyFile3Async(string sourceFilePath, string destinationFilePath, CancellationToken cancellationToken)
{
using (var ss = new FileStream(sourceFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var ds = new FileStream(destinationFilePath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
{
var queue = new ConcurrentQueue<byte[]>();
var readTask = Task.Run(async () =>
{
while (ss.Position < ss.Length)
{
var readBuffer = new byte[bufferSize];
await ss.ReadAsync(readBuffer, 0, readBuffer.Length, cancellationToken);
queue.Enqueue(readBuffer);
Debug.WriteLine("read {0:f3}%", (double)ss.Position / (double)ss.Length);
if (queue.Count >= 4)
{
do
{
Debug.WriteLine("read throttle");
await Task.Delay(throttleTime);
}
while (queue.Count > 1);
}
}
});
var writeTask = Task.Run(async () =>
{
while (ds.Position < ss.Length)
{
byte[] writeBuffer;
if (queue.IsEmpty || !queue.TryDequeue(out writeBuffer))
{
Debug.WriteLine("write throttle");
await Task.Delay(throttleTime);
continue;
}
await ds.WriteAsync(writeBuffer, 0, writeBuffer.Length, cancellationToken);
Debug.WriteLine("write {0:f3}%", (double)ds.Position / (double)ds.Length);
}
});
await Task.WhenAll(readTask, writeTask);
}
}
public static async Task CopyFile4Async(string sourceFilePath, string destinationFilePath, CancellationToken cancellationToken)
{
using (var ss = new FileStream(sourceFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var ds = new FileStream(destinationFilePath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
{
byte[] readBuffer = null;
byte[] transferBuffer = null;
byte[] writeBuffer = null;
bool isTransfered = true;
while (ds.Position < ss.Length)
{
var readTask = Task.Run(async () =>
{
var readLength = Math.Min(ss.Length - ss.Position, bufferSize);
if (readLength > 0)
{
if (isTransfered)
{
readBuffer = new byte[readLength];
await ss.ReadAsync(readBuffer, 0, readBuffer.Length, cancellationToken).ConfigureAwait(false);
Debug.WriteLine("read {0:f3}%", (double)ss.Position / (double)ss.Length);
}
isTransfered = Interlocked.CompareExchange<byte[]>(ref transferBuffer, readBuffer, null) == null;
}
});
var writeTask = Task.Run(async () =>
{
writeBuffer = Interlocked.Exchange<byte[]>(ref transferBuffer, null);
if (writeBuffer != null)
{
await ds.WriteAsync(writeBuffer, 0, writeBuffer.Length, cancellationToken).ConfigureAwait(false);
Debug.WriteLine("write {0:f3}%", (double)ds.Position / (double)ss.Length);
}
});
await Task.WhenAll(readTask, writeTask).ConfigureAwait(false);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment