I know progress bars by themselves have been already asked to death, but I'm having trouble with one. I need to download a file via FTP, I'm using WebClient, the downloaded data has to be saved to a byte array, but WebClient.DownloadDataAsync can't return it directly, so I have to use the DownloadDataCompleted method to acces the data. Everything up till there is ok, but the problem is that I can't "pause" the IEnumerator block without blocking the whole thread, and if I don't pause it, the app crashes because the byte array doesn't exist when it tries to access it. When the file to download was in http I used WWW and had no problems, but it had to be moved to FTP. Using WebClient.DownloadData works, but I was asked to include a progress bar. Anyway, hereĀ“s the code:
IEnumerator DownloadGame(Dictionary<string, string> settingsDict)
{
statusText = "Starting download...";
WebClient request = new WebClient();
request.Credentials = new NetworkCredential("user", "password");
request.DownloadDataCompleted += DownloadDataCompleted;
//byte[] fileData = request.DownloadData(settingsDict["downloadlink"]); This works, but is no good since it blocks the thread
request.DownloadDataAsync(new Uri(settingsDict["downloadlink"]),"somefilepath");
//do{}while(!downloadFinished); This also works but blocks the thread anyway
//Process the update
string tmpRoot = TMPFolder();
string tmpFolder = tmpRoot + Application.platform + settingsDict["latestVersion"] + "/";
if (!UnzipUpdate(fileData, tmpFolder))//fail here, in this case fileData is global
{
DeleteDirectory(tmpRoot);
yield break;
}
if (!ProcessUpdateData(tmpFolder))
{
DeleteDirectory(tmpRoot);
yield break;
}
DeleteDirectory(tmpRoot);
settingsDict["thisVersion"] = GetNextVersion();
}
void DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e){
fileData = e.Result;
downloadFinished = true;
}
you can use something like this based on a previous Stakoverflow post..
The easiest is to use BackgroundWorker and put your code into DoWork event handler. And report progress with BackgroundWorker.ReportProgress.
The basic idea:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
var ftpWebRequest = (FtpWebRequest)WebRequest.Create("ftp://xxx.com");
ftpWebRequest.Method = WebRequestMethods.Ftp.UploadFile; //or DownLoad
using (var inputStream = File.OpenRead(fileName))
using (var outputStream = ftpWebRequest.GetRequestStream())
{
var buffer = new byte[1024 * 1024];
int totalReadBytesCount = 0;
int readBytesCount;
while ((readBytesCount = inputStream.Read(buffer, 0, buffer.Length)) > 0)
{
outputStream.Write(buffer, 0, readBytesCount);
totalReadBytesCount += readBytesCount;
var progress = totalReadBytesCount * 100.0 / inputStream.Length;
backgroundWorker1.ReportProgress((int)progress);
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar.Value = e.ProgressPercentage;
}
Make sure WorkerReportsProgress is enabled
backgroundWorker2.WorkerReportsProgress = true;
With BackgroundWorker you can also easily implement upload cancellation.
Related
I'm trying to write to my uploadProgress progress bar's toolTip the current uploaded amount, so when the user mouseovers the progress bar, the can see the tooltip changing showing the uploaded amount against the file size.
the code I have so far give me the "busy" icon when I mouse over, until the file has finished uploaded, and then it shows the downloaded amount and file size.
Could someone help me get this working ?
private void uploadFile()
{
try
{
richTextBox1.AppendText("\n\nStarting file upload");
FtpWebRequest request =
(FtpWebRequest)WebRequest.Create("ftp://ftpsite.com/public_html/test.htm");
request.Credentials = new NetworkCredential("username", "password");
request.UsePassive = true;
request.UseBinary = true;
request.KeepAlive = true;
request.Method = WebRequestMethods.Ftp.UploadFile;
using (Stream fileStream = File.OpenRead(#"C:\path\testfile.UPLOAD"))
using (Stream ftpStream = request.GetRequestStream())
{
uploadProgress.Invoke(
(MethodInvoker)delegate {
uploadProgress.Maximum = (int)fileStream.Length; });
byte[] buffer = new byte[10240];
int read;
while ((read = fileStream.Read(buffer, 0, buffer.Length)) > 0)
{
ftpStream.Write(buffer, 0, read);
uploadProgress.Invoke(
(MethodInvoker)delegate {
uploadProgress.Value = (int)fileStream.Position;
toolTip1.SetToolTip(
uploadProgress, string.Format("{0} MB's / {1} MB's\n",
(uploadProgress.Value / 1024d / 1024d).ToString("0.00"),
(fileStream.Length / 1024d / 1024d).ToString("0.00")));
});
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Thanks
Your code works for me. Assuming you run the uploadFile on a background thread, like:
private void button1_Click(object sender, EventArgs e)
{
Task.Run(() => uploadFile());
}
See also How can we show progress bar for upload with FtpWebRequest
(though you know that link already)
You just update the tooltip too often, so it flickers.
I used the seemingly ridiculously easy code found here
protected void Capture(object sender, EventArgs e)
{
string url = txtUrl.Text.Trim();
Thread thread = new Thread(delegate()
{
using (WebBrowser browser = new WebBrowser())
{
browser.ScrollBarsEnabled = false;
browser.AllowNavigation = true;
browser.Navigate(url);
browser.Width = 1024;
browser.Height = 768;
browser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(DocumentCompleted);
while (browser.ReadyState != WebBrowserReadyState.Complete)
{
System.Windows.Forms.Application.DoEvents();
}
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
}
private void DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser browser = sender as WebBrowser;
using (Bitmap bitmap = new Bitmap(browser.Width, browser.Height))
{
browser.DrawToBitmap(bitmap, new Rectangle(0, 0, browser.Width, browser.Height));
using (MemoryStream stream = new MemoryStream())
{
bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
byte[] bytes = stream.ToArray();
imgScreenShot.Visible = true;
imgScreenShot.ImageUrl = "data:image/png;base64," + Convert.ToBase64String(bytes);
}
}
}
However, when I run it against a facebook url, or certain other sites, I get an all white result image. Sometimes I get some of the initial page, so it seems like a matter of timing what with all the new web technologies.
WebBrowser may be indicating a ReadyState of Complete, even though elements on the page are continuing to load.
If I add some Thread.Sleeps, it doesn't appear to help.
It is because DocumentCompleteddoesn't only fire once, which in your case is too early.
Have a look at this: Why is WebBrowser_DocumentCompleted() firing twice?
I'm going in circles searching and reading forums on how to solve this problems. After a day of trying I'm still at a loss how to solve my problem. I'm uploading a file and need to return the % in a a textbox. I'm having no problem with the upload portion and have no problems returning the values using the BackgroundWorker if I include all my code within the same class. However, what I'm doing is calling an ftp class from form1. I need the ftp class to return the percentage to form1 so I can can display in my UI and also need to have the server response codes returned from my ftp class to display in my form1. Everything was working ok before I tried to run this in a BackgroundWorker process, with the exception of course that the UI becomes unresponsive and returns all status messages after upload completed. Heres my code as it stands now. How do I get the percentage from ftp class and pass it back to form1, as well as the server response code once completed?
public partial class Form1 : Form
{
private BackgroundWorker bw = new BackgroundWorker();
private string ftpServer = #"ftp://10.0.0.0";
private string ftpUser = #"user";
private string ftpPass = #"pass";
private string ftpRemoteFile = #"myfile.exe";
private string ftpLocalFile = #"C:\Uploads\file.exe";
public Form1()
{
InitializeComponent();
bw.WorkerReportsProgress = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
}
private void sendButton_Click(object sender, EventArgs e)
{
progressRichTextBox.Text = "Sending";
if (bw.IsBusy != true)
{
bw.RunWorkerAsync();
}
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
ftp ftpClient = new ftp(ftpServer, ftpUser, ftpPass);
ftpClient.upload(progressRichTextBox, ftpRemoteFile, ftpLocalFile);
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (!(e.Error == null))
{
this.progressRichTextBox.Text = ("Error: " + e.Error.Message);
}
else
{
this.progressRichTextBox.Text = "Done!";
}
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.progressRichTextBox.Text = (e.ProgressPercentage.ToString() + "%");
}
}
And heres the ftp class:
public void upload(System.Windows.Forms.RichTextBox progressRichTextBox, string remoteFile, string localFile)
{
FileInfo fileInfo = new FileInfo(localFile);
/* Create an FTP Request */
ftpRequest = (FtpWebRequest)FtpWebRequest.Create(host + "/" + remoteFile);
/* Log in to the FTP Server with the User Name and Password Provided */
ftpRequest.Credentials = new NetworkCredential(user, pass);
/* Specify generic group name for faster upload */
ftpRequest.ConnectionGroupName = "AffiliateUpload";
/* Specify the Type of FTP Request */
ftpRequest.Method = WebRequestMethods.Ftp.UploadFile;
/* Server connection options */
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = true;
ftpRequest.KeepAlive = true;
ftpRequest.ContentLength = fileInfo.Length;
/* Buffer for the Data */
byte[] buff = new byte[bufferSize];
int contentLen;
/* Open a File Stream to Read the File for Upload */
FileStream localFileStream = fileInfo.OpenRead();
try
{
// Stream to which the file to be upload is written
ftpStream = ftpRequest.GetRequestStream();
// Read from the file stream 2kb at a time
contentLen = localFileStream.Read(buff, 0, bufferSize);
// Till Stream content ends
while (contentLen != 0)
{
// Write Content from the file stream to the
// FTP Upload Stream
ftpStream.Write(buff, 0, contentLen);
contentLen = localFileStream.Read(buff, 0, bufferSize);
}
// Close the file stream and the Request Stream
ftpStream.Close();
localFileStream.Close();
ftpRequest = null;
}
catch (Exception ex)
{
Console.WriteLine("Failed sending to " + host + "/" + remoteFile + " (" + ex.Message + ")");
}
}
You don't need to update progressRichTextBox in your upload method. Remove that parameter. You need to provide the worker object to your upload method and call worker.ReportProgress on it.
So i have the following code:
WebClient webClient = new WebClient();
Stream data = webClient.OpenRead("http://awesomeurl.com/file.zip");
UnzipFromStream(data, #"c:/dir/");
And i would like to have the data of that stream in a progress bar, just like if you would use WebClient with .DownloadProgressChanged
I cant however seem to figure out how to make it work...
Please note: i am using ICSharpCode.SharpZipLib
UPDATE #1.1
Ok, i managed to get the following code to work (it downloads and unzips + the complete msg is shown), however the progress bar is not updating:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// first, we need to get the exact size (in bytes) of the file we are downloading
Uri url = new Uri(filename);
System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse();
response.Close();
// gets the size of the file in bytes
Int64 iSize = response.ContentLength;
// keeps track of the total bytes downloaded so we can update the progress bar
Int64 iRunningByteTotal = 0;
string outFolder = folder;
// use the webclient object to download the file
using (System.Net.WebClient webClient = new WebClient())
{
// open the file at the remote URL for reading
using (System.IO.Stream zipStream = webClient.OpenRead(filename))
{
ZipInputStream zipInputStream = new ZipInputStream(zipStream);
ZipEntry zipEntry = zipInputStream.GetNextEntry();
while (zipEntry != null)
{
String entryFileName = zipEntry.Name;
// to remove the folder from the entry:- entryFileName = Path.GetFileName(entryFileName);
// Optionally match entrynames against a selection list here to skip as desired.
// The unpacked length is available in the zipEntry.Size property.
// Manipulate the output filename here as desired.
String fullZipToPath = Path.Combine(outFolder, entryFileName);
string directoryName = Path.GetDirectoryName(fullZipToPath);
if (directoryName.Length > 0)
Directory.CreateDirectory(directoryName);
// Unzip file in buffered chunks. This is just as fast as unpacking to a buffer the full size
// of the file, but does not waste memory.
// The "using" will close the stream even if an exception occurs.
using (FileStream streamWriter = File.Create(fullZipToPath))
{
int iByteSize = 0;
byte[] buffer = new byte[iSize]; // 4K is optimum
StreamUtils.Copy(zipInputStream, streamWriter, buffer);
while ((iByteSize = zipStream.Read(buffer, 0, buffer.Length)) > 0)
{
iRunningByteTotal += iByteSize;
// calculate the progress out of a base "100"
double dIndex = (double)(iRunningByteTotal);
double dTotal = (double)iSize;
double dProgressPercentage = (dIndex / dTotal);
int iProgressPercentage = (int)(dProgressPercentage * 100);
// update the progress bar
backgroundWorker1.ReportProgress(iProgressPercentage);
}
}
zipEntry = zipInputStream.GetNextEntry();
}
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("File download complete");
}
My software i designed uploads files using ftp to my sever I'm using the ftpwebrequest to do all uploading. When uploading a file 700mb it uploads about 500mbs then stops, it works fine when uploading smaller files the smaller files upload successfully but it just want work properly on large files. I have the uploading done in a background worker that reports the upload progress to a progress bar on the main client. When the background worker completes it executes the background worker completed function. The background worker completed function gets executed but the upload never completes and the progress bar is stuck at about 65 percent its like the client just stops uploading and executes the background worker completed function as though it completed uploading. What could be going wrong here the upload doesn't complete and the file dose not appear on the server here is the code that dose the uploading
void UploadFileInBackground_DoWork(object sender,DoWorkEventArgs e)
{
byte[] data;
int packetsize = 1024 * 8;
string Destination = UploadURI + cattext + "/" + ID + ".obj";
string source = DialogBrower.FileName;
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(Destination);
request.Credentials = new NetworkCredential("user", "pass");
request.Method = WebRequestMethods.Ftp.UploadFile;
request.UsePassive = true;
request.UseBinary = true;
request.KeepAlive = false;
using (FileStream fs = new FileStream(source, FileMode.Open, FileAccess.Read))
{
try
{
long filesize = fs.Length;
long sum = 0;
int count = 0;
data = new byte[packetsize];
Stream reqStream = request.GetRequestStream();
float totalpackits = filesize / packetsize;
float weightofpackit = 100 / totalpackits;
float percentage = 0;
while (sum < filesize)
{
List<string> statusparms = new List<string>();
count = fs.Read(data, 0, packetsize);
reqStream.Write(data, 0, count);
sum += count;
percentage += weightofpackit;
int percentagetotal = Convert.ToInt32(Math.Round(percentage));
statusparms.Add(sum.ToString());
statusparms.Add(filesize.ToString());
UploadFileInBackground.ReportProgress(percentagetotal, statusparms);
}
reqStream.Close();
uploadedname = uploadingname;
}
finally
{
fs.Dispose();
data = null;
}
}
}
Please try this instead:
request.UseBinary = false;
let's try this
request.KeepAlive = false;
to
request.KeepAlive = true;