I'm sending multiple files to my wrapper which sends files to ftp.I have to get the progress of the upload, so i have to use asycn method for uploading.The problem is, how can i call the uploader one by one, but also get the progress report?
Here's a solution if you want to wait for each file:
class FileUploader
{
private readonly Uri _destination;
public FileUploader(Uri destination)
{
_destination = destination;
}
public void UploadFiles(IEnumerable<string> fileNames)
{
foreach (var fileName in fileNames)
{
UploadFile(fileName);
}
}
private void UploadFile(string fileName)
{
var tcs = new TaskCompletionSource<bool>();
using (var client = new WebClient())
{
client.UploadProgressChanged += UploadProgressChangedHandler;
client.UploadFileCompleted += (sender, args) => UploadCompletedHandler(fileName, tcs, args);
client.UploadFileAsync(_destination, fileName);
tcs.Task.Wait();
}
}
private void UploadCompletedHandler(string fileName, TaskCompletionSource<bool> tcs, UploadFileCompletedEventArgs e)
{
if (e.Cancelled)
{
tcs.TrySetCanceled();
}
else if (e.Error != null)
{
tcs.TrySetException(e.Error);
}
else
{
tcs.TrySetResult(true);
}
}
private void UploadProgressChangedHandler(object sender, UploadProgressChangedEventArgs e)
{
// Handle progress, e.g.
System.Diagnostics.Debug.WriteLine(e.ProgressPercentage);
}
}
You have to subscribe to the UploadProgressChanged event:
var client = new WebClient();
client.UploadProgressChanged += (s, e) => System.Diagnostics.Debug.WriteLine(e.ProgressPercentage);
client.UploadFileAsync(new Uri("ftp://server/directory"), #"C:\temp\file.txt");
client.UploadFileCompleted += (s, e) => Task.Factory.StartNew(client.Dispose);
Related
The timer class
I'm checking when the TimeSpan ts variable if he gets to 0 then start counting 300 seconds down again.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Extract
{
public partial class TimeCounter : Label
{
public bool CountUp { get; set; }
public Timer _timer;
public TimeSpan ts = TimeSpan.FromSeconds(300);
public TimeCounter()
{
InitializeComponent();
StartCountDownTimer();
}
public void StartCountDownTimer()
{
_timer = new Timer
{
Interval = 1000,
Enabled = false
};
_timer.Tick += (sender, args) =>
{
if(ts == TimeSpan.FromSeconds(0))
{
ts = TimeSpan.FromSeconds(300);
}
if (CountUp)
{
ts = ts.Add(TimeSpan.FromSeconds(1));
}
else
{
ts = ts.Subtract(TimeSpan.FromSeconds(1));
}
this.Text = ts.ToString();
};
}
private void TimeCounter_Load(object sender, EventArgs e)
{
}
}
}
Then in Form1 I have a button click event where I start the timer and start downloading.
private void btnStart_Click(object sender, EventArgs e)
{
timeCounter1._timer.Enabled = true;
DownloadImages();
}
public async void DownloadImages()
{
CreateDownloadFolders();
urls = new List<string>();
lblStatus.Text = "Downloading...";
rad.GetRadarImages();
await Task.Delay(5000);
foreach (string link in rad.links)
{
urls.Add(link);
}
await sat.DownloadSatelliteAsync();
foreach (string link in sat.SatelliteUrls())
{
urls.Add(link);
}
urlsCounter = urls.Count;
await DownloadAsync();
}
And when the download is finished
private async Task DownloadAsync()
{
using (var client = new WebClient())
{
client.DownloadFileCompleted += (s, e) =>
{
if (e.Error == null)
{
urlsCounter--;
if (urlsCounter == 0)
{
GetImagesFiles();
timer1.Enabled = true;
timer2.Enabled = true;
lblStatus.Text = "Completed.";
}
}
};
client.DownloadProgressChanged += (s, e) => tracker.SetProgress(e.BytesReceived, e.TotalBytesToReceive);
client.DownloadProgressChanged += (s, e) => lblAmount.Text = tracker.SizeSuffix(e.BytesReceived) + "/" + tracker.SizeSuffix(e.TotalBytesToReceive);
client.DownloadProgressChanged += (s, e) => lblSpeed.Text = tracker.GetBytesPerSecondString();
client.DownloadProgressChanged += (s, e) => myLong = Convert.ToInt64(client.ResponseHeaders["Content-Length"]);
client.DownloadProgressChanged += (s, e) =>
{
progressBar1.Value = e.ProgressPercentage;
label1.Text = e.ProgressPercentage + "%";
};
for (int i = 0; i < urls.Count; i++)
{
tracker.NewFile();
if (urls[i].Contains("Radar"))
{
await client.DownloadFileTaskAsync(new Uri(urls[i]), radarFolderImagesDownload + "\\image" + radCounter + ".gif");
radCounter++;
}
else
{
await client.DownloadFileTaskAsync(new Uri(urls[i]), satelliteFolderImagesDownload + "\\image" + satCounter + ".gif");
satCounter++;
}
}
}
}
Now I want that when the counter TimeSpan ts variable in the TimeCounter class is reaching 00:00:00 start downloading again in form1 and so on. I'm not going to stop the timer I want that each 5 minutes start a new download count 5 minutes down and download nonstop.
I'm not sure where and how to call the DownloadImages() method in Form1 each time the timer has reached 0 ?
Add a custom event to your TimeCounter control, then raise it when the timer hits zero:
public partial class TimeCounter : Label
{
public delegate void dlgTimerTrigger(TimeCounter source);
public event dlgTimerTrigger TimerTrigger;
// ... other code not shown ...
if (ts == TimeSpan.FromSeconds(0))
{
ts = TimeSpan.FromSeconds(300);
if (TimerTrigger != null)
{
TimerTrigger(this);
}
}
// ... other code not shown ...
}
Now subscribe to that event in the Load() event of your form:
private void Form1_Load(object sender, EventArgs e)
{
timeCounter1.TimerTrigger += TimeCounter1_TimerTrigger;
}
private void TimeCounter1_TimerTrigger(TimeCounter source)
{
DownloadImages();
}
I am stuck and asking for your help, trying to make a software that check a txt file which is this format with CRC information and download the files inside that txt. These is just an example with same hash but in reality have different name, hash and size.
[FOLDER/FILE] [HASH] [FILESIZE]
./file1.dat f926038f 54
./Folder/file2.dat f926038f 54
./Folder/Subfolder/file3.dat f926038f 54
after I generate this type of information, I use this code to read where is the file...
private static void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
StreamReader streamReader = new StreamReader(new WebClient().OpenRead(Import.ServerURL + Import.PatchlistName));
while (!streamReader.EndOfStream)
ListProcessor.AddFile(streamReader.ReadLine());
}
and these code to check the list of that file and write them in current folder
internal class ListProcessor
{
public static void AddFile(string File) => Import.Files.Add(new Import.File()
{
Name = File.Split(' ')[0],
Hash = File.Split(' ')[1],
Size = Convert.ToInt64(File.Split(' ')[2])
});
}
the problem is that files outside of any folders or subfolders they are downloading perfectly, but inside any folder or subfolder the download does not work.
PS: This is the order from where it starts:
Main.cs
private void Btn_Run_Click(object sender, EventArgs e)
{
if (!this.Btn_Run.Enabled)
return;
ListDownloader.DownloadList();
}
ListDownloader.cs
internal class ListDownloader
{
public static void DownloadList()
{
Common.ChangeStatus("LISTDOWNLOAD");
Common.DisableStart();
BackgroundWorker backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += new DoWorkEventHandler(ListDownloader.backgroundWorker_DoWork);
backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(ListDownloader.backgroundWorker_RunWorkerCompleted);
if (backgroundWorker.IsBusy)
{
int num = (int) MessageBox.Show(Texts.GetText("UNKNOWNERROR", (object) "DownloadList isBusy"));
Application.Exit();
}
else
backgroundWorker.RunWorkerAsync();
}
private static void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
StreamReader streamReader = new StreamReader(new WebClient().OpenRead(Import.ServerURL + Import.PatchlistName));
while (!streamReader.EndOfStream)
ListProcessor.AddFile(streamReader.ReadLine());
}
private static void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
FileChecker.CheckFiles();
}
}
FileChecker.cs
internal class FileChecker
{
private static BackgroundWorker backgroundWorker = new BackgroundWorker();
public static void CheckFiles()
{
FileChecker.backgroundWorker.WorkerReportsProgress = true;
FileChecker.backgroundWorker.DoWork += new DoWorkEventHandler(FileChecker.backgroundWorker_DoWork);
FileChecker.backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(FileChecker.backgroundWorker_ProgressChanged);
FileChecker.backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(FileChecker.backgroundWorker_RunWorkerCompleted);
if (FileChecker.backgroundWorker.IsBusy)
{
int num = (int) MessageBox.Show(Texts.GetText("UNKNOWNERROR", (object) "CheckFiles isBusy"));
Application.Exit();
}
else
FileChecker.backgroundWorker.RunWorkerAsync();
}
private static void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
foreach (Import.File file in Import.Files)
{
Import.fullSize += file.Size;
FileChecker.backgroundWorker.ReportProgress(0, (object) Path.GetFileName(file.Name));
if (!System.IO.File.Exists(file.Name) || string.Compare(Common.GetHash(file.Name), file.Hash) != 0)
{
Import.OldFiles.Add(file.Name);
}
else
{
Import.completeSize += file.Size;
FileChecker.backgroundWorker.ReportProgress(1);
}
}
}
private static void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.ProgressPercentage == 0)
{
Common.ChangeStatus("CHECKFILE", e.UserState.ToString());
}
else
{
Common.UpdateCompleteProgress(Computer.Compute(Import.completeSize));
Common.UpdateCurrentProgress(Computer.Compute(Import.completeSize), 0.0);
}
}
private static void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
FileDownloader.DownloadFile();
}
private enum State
{
REPORT_NAME,
REPORT_PROGRESS,
}
}
and FileDownloader.cs
internal class FileDownloader
{
private static int curFile;
private static long lastBytes;
private static long currentBytes;
private static Stopwatch stopWatch = new Stopwatch();
public static void DownloadFile()
{
if (Import.OldFiles.Count <= 0)
{
Common.ChangeStatus("CHECKCOMPLETE");
Common.UpdateCurrentProgress(100L, 0.0);
Common.UpdateCompleteProgress(100L);
Starter.Start();
}
else if (FileDownloader.curFile >= Import.OldFiles.Count)
{
Common.ChangeStatus("DOWNLOADCOMPLETE");
Common.UpdateCurrentProgress(100L, 0.0);
Common.UpdateCompleteProgress(100L);
Starter.Start();
}
else
{
if (Import.OldFiles[FileDownloader.curFile].Contains("/"))
Directory.CreateDirectory(Path.GetDirectoryName(Import.OldFiles[FileDownloader.curFile]));
WebClient webClient = new WebClient();
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(FileDownloader.webClient_DownloadProgressChanged);
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(FileDownloader.webClient_DownloadFileCompleted);
FileDownloader.stopWatch.Start();
Common.ChangeStatus("DOWNLOADFILE", Import.OldFiles[FileDownloader.curFile]);
webClient.DownloadFileAsync(new Uri(Import.ServerURL + Import.OldFiles[FileDownloader.curFile]), Import.OldFiles[FileDownloader.curFile]);
}
}
private static void webClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
FileDownloader.currentBytes = FileDownloader.lastBytes + e.BytesReceived;
Common.UpdateCompleteProgress(Computer.Compute(Import.completeSize + FileDownloader.currentBytes));
Common.UpdateCurrentProgress((long) e.ProgressPercentage, Computer.ComputeDownloadSpeed((double) e.BytesReceived, FileDownloader.stopWatch));
}
private static void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
FileDownloader.lastBytes = FileDownloader.currentBytes;
Common.UpdateCurrentProgress(100L, 0.0);
++FileDownloader.curFile;
FileDownloader.stopWatch.Reset();
FileDownloader.DownloadFile();
}
}
I have this code below
public void DownloadFile(string payloadFile)
{
new Thread(() =>
{
using (WebClient wc = new WebClient())
{
// code removed for brevity
// How to I pass payloadFile parameter to two event handler below?
wc.DownloadProgressChanged += HandleDownloadProgress;
wc.DownloadFileCompleted += HandleDownloadComplete;
wc.DownloadFileAsync(uri, _downloadPath + payloadFile);
}
}).Start();
}
public void HandleDownloadComplete(object sender, AsyncCompletedEventArgs args)
{
// I need to get payloadFile parameter here
}
public void HandleDownloadProgress(object sender, DownloadProgressChangedEventArgs args)
{
// I need to get payloadFile parameter here
}
How to I pass payloadFile parameter to two event handler above?
Pass payloadFile as userToken parameter:
wc.DownloadFileAsync(uri, _downloadPath + payloadFile, payloadFile);
After that you can get it from args:
public void HandleDownloadComplete(object sender, AsyncCompletedEventArgs args)
{
string payloadFile = (string)args.UserState;
}
public void HandleDownloadProgress(object sender, DownloadProgressChangedEventArgs args)
{
string payloadFile = (string)args.UserState;
}
Im trying to use the progress bar to track my download, the only problem the progress value changes only after the file is downloaded to the computer and not during its download.
Here is my code, any help will be appreciated.
public void DownloadZaq()
{
using (WebClient zaq = new WebClient())
{
zaq.DownloadProgressChanged += new DownloadProgressChangedEventHandler(Zaq_DownloadProgressChanged);
zaq.DownloadFileCompleted += new AsyncCompletedEventHandler(Zaq_DownloadFileCompleted);
zaq.DownloadFileAsync(new Uri(http://example.com), #"c:\to\111.jpg");
}
}
public void Zaq_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
MessageBox.Show("download completed");
}
public void Zaq_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
I think that DownloadFileAsync is blocking the main thread somehow while checking the DNS. This is what I would try
WebClient zaq;
public void DownloadZaq()
{
zaq = new WebClient();
zaq.DownloadProgressChanged += new DownloadProgressChangedEventHandler(Zaq_DownloadProgressChanged);
zaq.DownloadFileCompleted += new AsyncCompletedEventHandler(Zaq_DownloadFileCompleted);
System.Threading.Tasks.Task.Run(() => // Workaround to allow Async call
{
try
{
zaq.DownloadFileAsync(new Uri(http://example.com), #"c:\to\111.jpg");
}
catch (Exception ex)
{
zag.Dispose();
}
});
}
public void Zaq_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
MessageBox.Show("download completed");
zag.Dispose();
}
public void Zaq_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
I want to use this method:
public static bool SynchronizeFiles(string source, string destination)
in BackgroundWorker. I define BackgroundWorker and add it in workerList. Than do this work one by one.
private void CopyIfIsReady(Save save)
{
if (save.isDriveReady && save.isFileChanged && save.isPeriodCompleted)
{
BackgroundWorker BW = new BackgroundWorker();
BW.DoWork += (obj, e) => backgroundWorker1_DoWork(save);
BW.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
workerList.Add(BW);
BW_timer.Start(500);
}
}
private void BWTimerCallBack(object state)
{
if (workerList.Count >= 0)
{
if(!workerList[0].IsBusy)
{
workerList[0].RunWorkerAsync();
}
}
else
{
BW_timer.Stop();
}
}
private void backgroundWorker1_DoWork(Save save)
{
SynchronizeFiles(save.sourceFolder, save.destFolder);
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
workerList.RemoveAt(0);
}
But how can I take return value of SynchronizeFiles in backgroundWorker1_RunWorkerCompleted.
You don't really need the backgroundWorker1_DoWork method since it's only wrapping the SynchronizeFiles method call. You can change the event handler the following way:
BW.DoWork += (obj, e) => { e.Result = SynchronizeFiles(save.sourceFolder, save.destFolder); }
Now inside backgroundWorker1_RunWorkerCompleted you can access the result via the e.Result property.