Created
January 28, 2015 13:12
-
-
Save emoacht/cc18a531a35dcec34b00 to your computer and use it in GitHub Desktop.
Copy a file with Stream.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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