我已經下載了並行編程小組的最後一個示例,並且我沒有成功正確添加取消下載一個文件。如何在新的並行編程庫的示例中下載文件時添加正確的取消文件
這裏是我最終有代碼:
var wreq = (HttpWebRequest)WebRequest.Create(uri);
// Fire start event
DownloadStarted(this, new DownloadStartedEventArgs(remoteFilePath));
long totalBytes = 0;
wreq.DownloadDataInFileAsync(tmpLocalFile,
cancellationTokenSource.Token,
allowResume,
totalBytesAction =>
{
totalBytes = totalBytesAction;
},
readBytes =>
{
Log.Debug("Progression : {0}/{1} => {2}%", readBytes, totalBytes, 100 * (double)readBytes/totalBytes);
DownloadProgress(this, new DownloadProgressEventArgs(remoteFilePath, readBytes, totalBytes, (int)(100 * readBytes/totalBytes)));
})
.ContinueWith((antecedent) =>
{
if (antecedent.IsFaulted)
Log.Debug(antecedent.Exception.Message);
//Fire end event
SetEndDownload(antecedent.IsCanceled, antecedent.Exception, tmpLocalFile, 0);
}, cancellationTokenSource.Token);
我想下載完成後,因此ContinueWith火結束事件。
我稍微改變了代碼樣本中添加的CancellationToken和2名代表去下載文件的大小,以及下載的進展:
return webRequest.GetResponseAsync()
.ContinueWith(response =>
{
if (totalBytesAction != null)
totalBytesAction(response.Result.ContentLength);
response.Result.GetResponseStream().WriteAllBytesAsync(filePath, ct, resumeDownload, progressAction).Wait(ct);
}, ct);
我不得不添加通話到Wait函數,因爲如果我不這樣做,該方法退出並且結束事件被觸發得太早。
下面是修改後的方法擴展(大量的代碼,道歉:P)
public static Task WriteAllBytesAsync(this Stream stream, string filePath, CancellationToken ct, bool resumeDownload = false, Action<long> progressAction = null)
{
if (stream == null) throw new ArgumentNullException("stream");
// Copy from the source stream to the memory stream and return the copied data
return stream.CopyStreamToFileAsync(filePath, ct, resumeDownload, progressAction);
}
public static Task CopyStreamToFileAsync(this Stream source, string destinationPath, CancellationToken ct, bool resumeDownload = false, Action<long> progressAction = null)
{
if (source == null) throw new ArgumentNullException("source");
if (destinationPath == null) throw new ArgumentNullException("destinationPath");
// Open the output file for writing
var destinationStream = FileAsync.OpenWrite(destinationPath);
// Copy the source to the destination stream, then close the output file.
return CopyStreamToStreamAsync(source, destinationStream, ct, progressAction).ContinueWith(t =>
{
var e = t.Exception;
destinationStream.Close();
if (e != null)
throw e;
}, ct, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Current);
}
public static Task CopyStreamToStreamAsync(this Stream source, Stream destination, CancellationToken ct, Action<long> progressAction = null)
{
if (source == null) throw new ArgumentNullException("source");
if (destination == null) throw new ArgumentNullException("destination");
return Task.Factory.Iterate(CopyStreamIterator(source, destination, ct, progressAction));
}
private static IEnumerable<Task> CopyStreamIterator(Stream input, Stream output, CancellationToken ct, Action<long> progressAction = null)
{
// Create two buffers. One will be used for the current read operation and one for the current
// write operation. We'll continually swap back and forth between them.
byte[][] buffers = new byte[2][] { new byte[BUFFER_SIZE], new byte[BUFFER_SIZE] };
int filledBufferNum = 0;
Task writeTask = null;
int readBytes = 0;
// Until there's no more data to be read or cancellation
while (true)
{
ct.ThrowIfCancellationRequested();
// Read from the input asynchronously
var readTask = input.ReadAsync(buffers[filledBufferNum], 0, buffers[filledBufferNum].Length);
// If we have no pending write operations, just yield until the read operation has
// completed. If we have both a pending read and a pending write, yield until both the read
// and the write have completed.
yield return writeTask == null
? readTask
: Task.Factory.ContinueWhenAll(new[]
{
readTask,
writeTask
},
tasks => tasks.PropagateExceptions());
// If no data was read, nothing more to do.
if (readTask.Result <= 0)
break;
readBytes += readTask.Result;
if (progressAction != null)
progressAction(readBytes);
// Otherwise, write the written data out to the file
writeTask = output.WriteAsync(buffers[filledBufferNum], 0, readTask.Result);
// Swap buffers
filledBufferNum ^= 1;
}
}
因此,基本上,在稱爲方法的鏈的末端,我讓的CancellationToken拋出OperationCanceledException如果一個取消具有被請求。
我希望在吸引人的代碼中獲得IsFaulted == true,並用取消的標誌和正確的異常觸發結束事件。
但我得到的是上線
response.Result.GetResponseStream()WriteAllBytesAsync(文件路徑,CT,resumeDownload,progressAction).Wait(CT)未處理的異常。
告訴我,我沒有發現AggregateException。我嘗試了各種各樣的東西,但我沒有成功地讓整個事情正常工作。
你們有沒有玩過這個圖書館,可以幫助我嗎?
在此先感謝
邁克