İnternet'ten dosya indiren basit bir konsol uygulamaları yapıyorum.
I had problems with WebClient HttpClient kullanarak uygulamamı yazmaya karar verdim.Stream.CopyToAsync, ilerleme raporlamasıyla birlikte - kopyalama tamamlandıktan sonra bile rapor ediliyor
Temel olarak, üstbilgileri okumak için istek yapıyorum, ReadAsStreamAsync
kullanarak CopyToAsync
kullanarak yerel dosyaya kopyalarım akışı alıyorum.
Ben IProgress destekler akışı için uzatma yöntemi buldum:
public static class StreamExtensions
{
public static async Task CopyToAsync(this Stream source, Stream destination, IProgress<long> progress, CancellationToken cancellationToken = default(CancellationToken), int bufferSize = 0x1000)
{
var buffer = new byte[bufferSize];
int bytesRead;
long totalRead = 0;
while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken)) > 0)
{
await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
totalRead += bytesRead;
//Thread.Sleep(10);
progress.Report(totalRead);
}
}
}
My uygulama çalışmalarını, ama yanlış ilerleme bilgi alabilirsiniz.
file1.tmp 60.95%
file2.tmp 98.09%
file1.tmp 60.98%
file2.tmp 98.21%
file2.tmp 98.17%
file2.tmp 98.25%
file1.tmp 61.02%
file2.tmp 98.41%
file2.tmp downloaded
file2.tmp 98.29%
file2.tmp 98.37%
file1.tmp 61.06%
file2.tmp 89.27%
file2.tmp 89.31%
file2.tmp 98.33%
file2.tmp 98.45%
file2.tmp 98.48%
file1.tmp 61.10%
file1.tmp 61.14%
file2.tmp 98.52%
file1.tmp 61.22%
file2.tmp 98.60%
file2.tmp 98.56%
file1.tmp 61.30%
file2.tmp 98.88%
file2.tmp 90.44%
file1.tmp 61.53%
file2.tmp 98.72%
file1.tmp 61.41%
file1.tmp 61.73%
file2.tmp 98.80%
file1.tmp 61.26%
file1.tmp 61.49%
file1.tmp 61.57%
file1.tmp 61.69%
...
file1.tmp 99.31%
file1.tmp 98.84%
file1.tmp 98.80%
file1.tmp 99.04%
file1.tmp 99.43%
file1.tmp 99.12%
file1.tmp 99.00%
file1.tmp downloaded
file1.tmp 100.00%
file1.tmp 98.73%
file1.tmp 98.88%
file1.tmp 99.47%
file1.tmp 99.98%
file1.tmp 99.90%
file1.tmp 98.96%
file1.tmp 99.78%
file1.tmp 99.99%
file1.tmp 99.74%
file1.tmp 99.59%
file1.tmp 99.94%
file1.tmp 98.49%
file1.tmp 98.53%
ALL FILES DOWNLOADED
file1.tmp 99.55%
file1.tmp 98.41%
file1.tmp 99.62%
file1.tmp 98.34%
file1.tmp 99.66%
file1.tmp 98.69%
file1.tmp 98.37%
Sen Dosya2 indirilmesini bilgi var görebileceğiniz gibi, ama yine de Dosya1 ile aynı, CopyToAsync
gelen ilerleme raporu alıyorum: Örneğin
2 dosya indirme Ben çıktı penceresinde görüyoruz. bu nedenle
Bazen bu tuhaf konsol çıktısını almak: O ayıklama bilgisini aldıktan sonra
await streamToReadFrom.CopyToAsync(streamToWriteTo, progress, source.Token,0x2000);
Debug.WriteLine(filename+" downloaded");
:
İdeal dediğim zaman daha emin olmak istiyorum ilerleme kaydedilmedi (dosya indirildi). await
'un benim sorunumu çözeceğini düşündüm, ama değil.
Bunu nasıl düzeltebilirim? Geçici bir çözüm olarak, ilerlemeyi bildirmeden hemen önce Thread.leep'ı CopyToAsync
'a ekliyorum.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace AsyncDownloadTest
{
class Program
{
private const string LocalPath = @"D:\TEMP";
static void Main()
{
try
{
var filesToDownlad = new List<Tuple<string, string>>
{
new Tuple<string, string>("file1.tmp", "http://ipv4.download.thinkbroadband.com/10MB.zip"),
new Tuple<string, string>("file2.tmp", "http://ipv4.download.thinkbroadband.com/10MB.zip")
};
_consolePosition = -1;
Console.CursorVisible = false;
Parallel.ForEach(filesToDownlad, new ParallelOptions { MaxDegreeOfParallelism = 4 }, doc =>
{
DownloadFile(doc.Item2,doc.Item1).Wait();
});
Debug.WriteLine("ALL FILES DOWNLOADED");
Console.CursorVisible = true;
}
catch (Exception e)
{
Console.WriteLine(e);
Console.ReadLine();
}
}
private static readonly object ConsoleLock = new object();
private static int _consolePosition;
static readonly CancellationTokenSource source = new CancellationTokenSource();
private static async Task DownloadFile(string url, string filename)
{
int currenctLineNumber = 0;
int currectProgress = 0;
try
{
lock (ConsoleLock)
{
_consolePosition++;
currenctLineNumber = _consolePosition;
}
long fileSize = -1;
IProgress<long> progress = new Progress<long>(value =>
{
decimal tmp = (decimal)(value * 100)/fileSize;
if (tmp != currectProgress && tmp > currectProgress)
{
lock (ConsoleLock)
{
currectProgress = (int)tmp;
Console.CursorTop = currenctLineNumber;
Console.CursorLeft = 0;
Console.Write("{0,10} - {2,11} - {1,6:N2}%", filename, tmp, "DOWNLOADING");
}
Debug.WriteLine("{1} {0:N2}%", tmp, filename);
}
});
using (HttpClient client = new HttpClient())
{
using (HttpResponseMessage response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, source.Token))
{
response.EnsureSuccessStatusCode();
if (response.Content.Headers.ContentLength.HasValue) fileSize = response.Content.Headers.ContentLength.Value;
if (response.Content.Headers.ContentDisposition != null)
{
var tmp = response.Content.Headers.ContentDisposition.FileName.Replace("\"", "");
Debug.WriteLine("Real name: {0}",tmp);
}
using (Stream streamToReadFrom = await response.Content.ReadAsStreamAsync())
{
using (Stream streamToWriteTo = File.Open(Path.Combine(LocalPath, filename), FileMode.Create, FileAccess.Write))
{
await streamToReadFrom.CopyToAsync(streamToWriteTo, progress, source.Token,0x2000);
Debug.WriteLine(filename+" downloaded");
lock (ConsoleLock)
{
Console.CursorTop = currenctLineNumber;
Console.CursorLeft = 0;
var oldColor = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Green;
Console.Write("{0,10} - {2,11} - {1,6:N2}%", filename, 100, "SUCCESS");
Console.ForegroundColor = oldColor;
}
}
}
}
}
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
lock (ConsoleLock)
{
Console.CursorTop = currenctLineNumber;
Console.CursorLeft = 0;
var oldColor = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Red;
Console.Write("{0,10} - {2,11} - {1,6:N2}%", filename, currectProgress, "ERROR");
Console.ForegroundColor = oldColor;
}
}
}
}
public static class StreamExtensions
{
public static async Task CopyToAsync(this Stream source, Stream destination, IProgress<long> progress, CancellationToken cancellationToken = default(CancellationToken), int bufferSize = 0x1000)
{
var buffer = new byte[bufferSize];
int bytesRead;
long totalRead = 0;
while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken)) > 0)
{
await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
totalRead += bytesRead;
Thread.Sleep(10);
progress.Report(totalRead);
}
}
}
}
Bunun, "async" kullanılarak değil, konsolunuza çıktı verirken yanlış satırı/sütunu belirleyen kodunuzla ilgili bir şey olduğunu sanmıyorum. "Lock" unla ilgili bir şey yanlıştı, ama daha fazla araştırmadım. – Krumelur
@Krumelur Yorumunuz için teşekkür ederim, konsol ile ilgili kodu kaldırdığımda bile ben hala "file2.tmp indirildi" VS Output penceresinde görebiliyorum ama bundan sonra hala sorularımda olduğu gibi ilerleme raporları alıyorum (ikinci kod bölümü) 'file1.tmp% 60.95' ile başlayan yıldızlar – Misiu
Dikkatli olun 'DownloadFile (doc.Item2, doc.Item1) .Wait();' 'Parallel.ForEach' içinde,' Paralel' sınıfı arama iş parçacığı kullanır Çalışan iş parçacıklarından biri olarak, bu iş parçacığı bir "SynchronizationContext" ise, programın kilitlenmesine neden olur. 'Parallel' yerine [TPL Dataflow] 'a (https://msdn.microsoft.com/en-us/library/hh228603 (v = vs.110) .aspx) bakmak isteyebilirsiniz. Async işlevlerini desteklemeyi destekleyin, böylece '' .Filge '' yerine doğrudan '.Wait()' demeye gerek kalmadan 'DownloadFile'ı geçebilirsiniz. –