Async ftp file download with progress bar - c#

So I am trying to download file with FTP and want to show current progress on a progress bar component. I run task like this with custom FtpClient class:
SaveFileDialog sfd = new SaveFileDialog();
if (sfd.ShowDialog() == true)
{
pBar.Visibility = Visibility.Visible;
string status = "";
string filename = entry.FileName.Text;
await Task.Run(() =>
{
status = client.DownloadFile(filename, sfd.FileName, pBar);
});
statusBox.Text = status.Substring(4);
}
public string DownloadFile(string source, string dest, ProgressBar pBar)
{
FtpWebRequest sizeRequest = CreateRequest(CombinePaths(url, source), WebRequestMethods.Ftp.GetFileSize); // creates FtpWebRequest and assigns method
FtpWebResponse sizeResponse = (FtpWebResponse)sizeRequest.GetResponse();
if (sizeResponse.ContentLength <= 0) // if server does not support SIZE
pBar.IsIndeterminate = true;
else
{
pBar.IsIndeterminate = false; // fails here since progress bar is in the another thread
pBar.Maximum = sizeResponse.ContentLength;
pBar.Value = 0;
}
byte[] buffer = new byte[buffSize];
using (FtpWebResponse dlResponse = (FtpWebResponse)dlRequest.GetResponse())
{
using (Stream stream = dlResponse.GetResponseStream())
{
using (FileStream fs = new FileStream(dest, FileMode.OpenOrCreate))
{
int readCount = stream.Read(buffer, 0, buffSize);
while (readCount > 0)
{
fs.Write(buffer, 0, readCount);
pBar.Value = pBar.Value + readCount;
readCount = stream.Read(buffer, 0, buffSize);
}
}
}
return dlResponse.StatusDescription;
}
Is there a way to make this work? Since I am downloading and trying to update UI I don't know is there is a way to do what I want

pBar.Dispatcher.Invoke(() =>
{
if (GetFileSize(source) <= 0)
pBar.IsIndeterminate = true;
else
{
pBar.IsIndeterminate = false;
pBar.Maximum = GetFileSize(source);
pBar.Value = 0;
}
});
// code...
pBar.Dispatcher.Invoke(() =>
{
pBar.Value = pBar.Value + readCount;
});
Used dispatcher to update progress bar, works flawlessly

Related

can't download from HttpWebRequest more than once

I am new to C# and trying to write a download manager with HttpWebRequest.
my manager calls a new class for breaking file into chunks for every file and that class calls a new downloader class.
my code for download is:
private void StartDownload()
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);
Console.WriteLine("request");
request.AddRange((int)_startPos, (int)_endPos);
WebResponse res = request.GetResponse();
Console.WriteLine("res: "+res);
RequestContentLength = 0;
try
{
bool isFinished = false;
isDownloading = true;
double speed = 0;
using (var responseStream = res.GetResponseStream())
{
using (FileStream localFileStream = new FileStream(FilePath, FileMode.Append))
{
Console.WriteLine("download started - "+ Url);
var buffer = new byte[4096];
int bytesRead;
DateTime lastDate = DateTime.Now;
int lastDownloaded = 0;
while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0 && isDownloading)
{
totalBytesRead += bytesRead;
if ((DateTime.Now - lastDate).TotalSeconds >= 1)
{
lastDate = DateTime.Now;
speed = totalBytesRead - lastDownloaded;
lastDownloaded = totalBytesRead;
}
RequestContentLength += bytesRead;
localFileStream.Write(buffer, 0, bytesRead);
double percentage = totalBytesRead * 100 / FileHeader.FileSize;
onDownloadProgress?.Invoke(ID, fname, percentage, totalBytesRead, FileHeader.FileSize, speed);
}
isFinished = true;
}
}
if (isFinished) {
onDownloadFinished?.Invoke(ID, fname, true, "success");
}
else
{
onDownloadFinished?.Invoke(ID, fname, false, "error");
}
isDownloading = false;
}
catch (Exception ex)
{
isDownloading = false;
onDownloadFinished?.Invoke(ID, fname, false, ex.Message);
}
}
the code works fine for the FIRST download ( I cropped the rest to make it shorter) but when I call it after first download I get Console.WriteLine("request"); to output but the rest stops and after a minute or two I get a timeout error at WebResponse res = request.GetResponse();
I couldn't name my exact problem and couldn't find a solution.
there are some similar posts about this and I tried most of them but doesn't work for me.

C# - How can I receive filename and file from my Java app

I am very new to Java and C#. I have a java app that is sending the filename and file to a C# client using TCP Socket. I receive the data but it is corrupt when writing. I do not know how to first read the file name and then rest of the data to write the file.
I have written code that if I just send the file from my java app I successfully receive it on my C# app and write it successfully. This works 100%. Now I want to send the name and file.
Java code sending the data:
try {
System.out.println("Connecting...");
File file = new File(Environment.getExternalStorageDirectory(), backup_folder);
File[] Files = file.listFiles();
OutputStream os = m_socket.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
dos.writeInt(Files.length);
for (int count = 0; count < Files.length; count++) {
dos.writeUTF(Files[count].getName());
}
for (int count = 0; count < Files.length; count++) {
int filesize = (int) Files[count].length();
dos.writeInt(filesize);
}
for (int count = 0; count < Files.length; count++) {
int filesize = (int) Files[count].length();
byte[] buffer = new byte[filesize];
FileInputStream fis = new FileInputStream(Files[count].toString());
BufferedInputStream bis = new BufferedInputStream(fis);
//Sending file name and file size to the server
bis.read(buffer, 0, buffer.length); //This line is important
dos.write(buffer, 0, buffer.length);
dos.flush();
//close socket connection
//socket.close();
}
m_socket.close();
} catch (Exception e) {
System.out.println("Error::" + e);
//System.out.println(e.getMessage());
//e.printStackTrace();
//Log.i("******* :( ", "UnknownHostException");
}
}
C# code (this is where I am having my problem)
private void WaitConnection()
{
toolStripStatusLabel2.Visible = true;
toolStripStatusLabel1.Visible = false;
while (true){
m_listener.Start();
m_client = m_listener.AcceptTcpClient();
if (m_client.Connected == true)
{
this.Invoke((MethodInvoker)delegate
{
this.toolStripStatusLabel4.Visible = false;
this.toolStripStatusLabel5.Visible = false;
this.toolStripStatusLabel3.Visible = true;
});
}
using (var stream = m_client.GetStream())
using (var output = File.Create("C:\\Stocktake\\EDADatabase.db"))
{
byte[] buffer;
buffer = new byte[1024];
int bytesRead = -1;
progressBar1.BeginInvoke(new MethodInvoker(delegate { progressBar1.Maximum = 50; })); //Set Progessbar maximum
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
{
var xml = Encoding.UTF8.GetString(buffer,0,bytesRead);
string rec = System.Text.Encoding.ASCII.GetString(buffer, 0, bytesRead);
output.Write(buffer, 0, bytesRead);
progressBar1.Invoke(new updatebar(this.UpdateProgress));
}
if (bytesRead == 0)
{
Completed = true;
this.Invoke((MethodInvoker)delegate
{
this.m_client.GetStream().Close();
this.m_client.Dispose();
this.m_listener.Stop();
this.toolStripStatusLabel3.Visible = false;
this.toolStripStatusLabel5.Visible = true;
});
progressBar1.Invoke(new updatebar(this.UpdateProgress));
//break;
}
}
}
}
All I want to do is read the file name and use the file name to read and save the data to my pc.

How can i download a file faster?

I have made a download program in C#. It is a queue downloader.
You can see how it works here: Click Express Downloader
Is there any faster method to download?
Here is the method i use, it must support resume support.
private void Download(object startPoint)
{
try
{
try
{
//int startPointInt = Convert.ToInt32(startPoint);
Int64 startPointInt = Convert.ToInt64(startPoint);
webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.AddRange(startPointInt);
webRequest.Credentials = CredentialCache.DefaultCredentials;
webResponse = (HttpWebResponse)webRequest.GetResponse();
Int64 fileSize = webResponse.ContentLength;
strResponse = webResponse.GetResponseStream();
if (startPointInt == 0)
{
strLocal = new FileStream(txtPath.Text + "\\" + filename, FileMode.Create, FileAccess.Write, FileShare.None);
}
else
{
strLocal = new FileStream(txtPath.Text + "\\" + filename, FileMode.Append, FileAccess.Write, FileShare.None);
}
int bytesSize = 0;
byte[] downBuffer = new byte[4096];
while ((bytesSize = strResponse.Read(downBuffer, 0, downBuffer.Length)) > 0)
{
strLocal.Write(downBuffer, 0, bytesSize);
this.Invoke(new UpdateProgessCallback(this.UpdateProgress), new object[] { strLocal.Length, fileSize + startPointInt });
if (goPause == true)
{
break;
}
}
}
catch { }
}
finally
{
strResponse.Close();
strLocal.Close();
}
}
You have to do two things,
Get faster bandwidth
Change block size from 4096 to something like 8192 or any number which can be hold in memory easily.

How can I upload more than one file to my FTP site?

The idea is that if I selected more than one file then upload one file when, then when it finishes to upload then upload the next one and so on.
I changed the filedialoug to be able to select multi:
private void btnBrowse_Click(object sender, EventArgs e)
{
openFileDialog1.Multiselect = true;
if (this.openFileDialog1.ShowDialog() != DialogResult.Cancel)
this.txtUploadFile.Text = this.openFileDialog1.FileName;
}
I can select more than one file the problem is that when using a breakpoint I see on this.txtUploadFile.Text one file only the first I selected. txtUploadFile is a textBox.
The first thing is: how can I see on the textBox(txtUploadFile) all the selected files and not only one? Or how can I get some indication that all the files I selected really selected? Maybe to show somehow in the textBox something that all files selected?
The important part is: how do I upload all the selected files one by one?
This is the button click event that starting the files uploading:
private void btnUpload_Click(object sender, EventArgs e)
{
if(this.ftpProgress1.IsBusy)
{
this.ftpProgress1.CancelAsync();
this.btnUpload.Text = "Upload";
}
else
{
FtpSettings f = new FtpSettings();
f.Host = this.txtHost.Text;
f.Username = this.txtUsername.Text;
f.Password = this.txtPassword.Text;
f.TargetFolder = this.txtDir.Text;
f.SourceFile = this.txtUploadFile.Text;
f.Passive = this.chkPassive.Checked;
try
{
f.Port = Int32.Parse(this.txtPort.Text);
}
catch { }
this.toolStripProgressBar1.Visible = true;
this.ftpProgress1.RunWorkerAsync(f);
this.btnUpload.Text = "Cancel";
}
}
I also have a backgroundworker with a progressBar so each file that is uploading the progressBar should show the progress of the uploading today it's showing for one file since I can upload only one file:
private void ftpProgress1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.toolStripStatusLabel1.Text = e.UserState.ToString(); // The message will be something like: 45 Kb / 102.12 Mb
this.toolStripProgressBar1.Value = Math.Min(this.toolStripProgressBar1.Maximum, e.ProgressPercentage);
}
private void ftpProgress1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if(e.Error != null)
MessageBox.Show(e.Error.ToString(), "FTP error");
else if(e.Cancelled)
this.toolStripStatusLabel1.Text = "Upload Cancelled";
else
this.toolStripStatusLabel1.Text = "Upload Complete";
this.btnUpload.Text = "Upload";
this.toolStripProgressBar1.Visible = true;
}
And last the class of the FTP uploader:
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Text;
namespace FTP_ProgressBar
{
public partial class FtpProgress : BackgroundWorker
{
public static string ConnectionError;
private FtpSettings f;
public FtpProgress()
{
InitializeComponent();
}
public FtpProgress(IContainer container)
{
container.Add(this);
InitializeComponent();
}
private void FtpProgress_DoWork(object sender, DoWorkEventArgs e)
{
try
{
BackgroundWorker bw = sender as BackgroundWorker;
f = e.Argument as FtpSettings;
string UploadPath = String.Format("{0}/{1}{2}", f.Host, f.TargetFolder == "" ? "" : f.TargetFolder + "/", Path.GetFileName(f.SourceFile));
if (!UploadPath.ToLower().StartsWith("ftp://"))
UploadPath = "ftp://" + UploadPath;
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(UploadPath);
request.UseBinary = true;
request.UsePassive = f.Passive;
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Timeout = 300000;
request.Credentials = new NetworkCredential(f.Username, f.Password);
long FileSize = new FileInfo(f.SourceFile).Length;
string FileSizeDescription = GetFileSize(FileSize);
int ChunkSize = 4096, NumRetries = 0, MaxRetries = 50;
long SentBytes = 0;
byte[] Buffer = new byte[ChunkSize];
using (Stream requestStream = request.GetRequestStream())
{
using (FileStream fs = File.Open(f.SourceFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
int BytesRead = fs.Read(Buffer, 0, ChunkSize);
while (BytesRead > 0)
{
try
{
if (bw.CancellationPending)
return;
requestStream.Write(Buffer, 0, BytesRead);
SentBytes += BytesRead;
string SummaryText = String.Format("Transferred {0} / {1}", GetFileSize(SentBytes), FileSizeDescription);
bw.ReportProgress((int)(((decimal)SentBytes / (decimal)FileSize) * 100), SummaryText);
}
catch (Exception ex)
{
Debug.WriteLine("Exception: " + ex.ToString());
if (NumRetries++ < MaxRetries)
{
fs.Position -= BytesRead;
}
else
{
throw new Exception(String.Format("Error occurred during upload, too many retries. \n{0}", ex.ToString()));
}
}
BytesRead = fs.Read(Buffer, 0, ChunkSize);
}
}
}
using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
System.Diagnostics.Debug.WriteLine(String.Format("Upload File Complete, status {0}", response.StatusDescription));
}
catch (WebException ex)
{
switch (ex.Status)
{
case WebExceptionStatus.NameResolutionFailure:
ConnectionError = "Error: Please check the ftp address";
break;
case WebExceptionStatus.Timeout:
ConnectionError = "Error: Timout Request";
break;
}
}
}
public static string GetFileSize(long numBytes)
{
string fileSize = "";
if(numBytes > 1073741824)
fileSize = String.Format("{0:0.00} Gb", (double)numBytes / 1073741824);
else if(numBytes > 1048576)
fileSize = String.Format("{0:0.00} Mb", (double)numBytes / 1048576);
else
fileSize = String.Format("{0:0} Kb", (double)numBytes / 1024);
if(fileSize == "0 Kb")
fileSize = "1 Kb";
return fileSize;
}
}
public class FtpSettings
{
public string Host, Username, Password, TargetFolder, SourceFile;
public bool Passive;
public int Port = 21;
}
}
It is a bit long, but I couldn't find a way to narrow the code since it's all connected to each other.
What I need it to do is if I selected more than one file make something like a queue and automatic upload one file when finished upload the next file and so on until the last file.
Today I can upload only one file. Single file each time.
I need that it will automatically upload all the selected files. Using the progressBar and the backgroundworker like it is now.
Here is a procedure how to upload multiple files from the directory where ftp - an address of ftp server:
private void uploadFTP(DirectoryInfo d, string ftp)
{
FileInfo[] flist = d.GetFiles();
if (flist.GetLength(0) > 0)
{
foreach (FileInfo txf in flist)
{
FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(ftp + txf.Name);
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential("username", "password");
request.UsePassive = true;
request.UseBinary = true;
request.KeepAlive = false;
FileStream stream = File.OpenRead(txf.FullName);
byte[] buffer = new byte[stream.Length];
stream.Read(buffer, 0, buffer.Length);
stream.Close();
Stream reqStream = request.GetRequestStream();
reqStream.Write(buffer, 0, buffer.Length);
reqStream.Close();
txf.Delete();
}
}
}
You should be using
OpenFileDialog1.FileNames
And iterate on those elements to upload them one by one.
FileNames Property

to post image file in windows phone 7 application

I am developing an application for windows phone 7.From here I want to upload an image file to the remote server.I am using the following code to receive the file at my receiving end:
if (Request.Files.Count > 0)
{
string UserName = Request.QueryString["SomeString"].ToString();
HttpFileCollection MyFilecollection = Request.Files;
string ImageName = System.Guid.NewGuid().ToString() + MyFilecollection[0].FileName;
MyFilecollection[0].SaveAs(Server.MapPath("~/Images/" + ImageName));
}
Now my problem is, how can I post the file from my windows phone 7 platform (using PhotoChooserTask).I have tried the following code but with no success.(the following code is called from the PhotoChooserTask completed event handler.
private void UploadFile(string fileName, Stream data)
{
char[] ch=new char[1];
ch[0] = '\\';
string [] flname=fileName.Split(ch);
UriBuilder ub = new UriBuilder("http://www.Mywebsite.com?SomeString="+ussi );
ub.Query = string.Format("name={0}", flname[6]);
WebClient c = new WebClient();
c.OpenWriteCompleted += (sender, e) =>
{
PushData(data, e.Result);
e.Result.Close();
data.Close();
};
c.OpenWriteAsync(ub.Uri);
}
private void PushData(Stream input, Stream output)
{
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) != 0)
{
output.Write(buffer, 0, bytesRead);
}
}
Please help me out to get out from this problem.
Thanks
I was able to get this working, but not using the Files collection. From my post at http://chriskoenig.net/2011/08/19/upload-files-from-windows-phone/:
Client Code
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
}
private void SelectButton_Click(object sender, RoutedEventArgs e)
{
PhotoChooserTask task = new PhotoChooserTask();
task.Completed += task_Completed;
task.Show();
}
private void task_Completed(object sender, PhotoResult e)
{
if (e.TaskResult != TaskResult.OK)
return;
const int BLOCK_SIZE = 4096;
Uri uri = new Uri("http://localhost:4223/File/Upload", UriKind.Absolute);
WebClient wc = new WebClient();
wc.AllowReadStreamBuffering = true;
wc.AllowWriteStreamBuffering = true;
// what to do when write stream is open
wc.OpenWriteCompleted += (s, args) =>
{
using (BinaryReader br = new BinaryReader(e.ChosenPhoto))
{
using (BinaryWriter bw = new BinaryWriter(args.Result))
{
long bCount = 0;
long fileSize = e.ChosenPhoto.Length;
byte[] bytes = new byte[BLOCK_SIZE];
do
{
bytes = br.ReadBytes(BLOCK_SIZE);
bCount += bytes.Length;
bw.Write(bytes);
} while (bCount < fileSize);
}
}
};
// what to do when writing is complete
wc.WriteStreamClosed += (s, args) =>
{
MessageBox.Show("Send Complete");
};
// Write to the WebClient
wc.OpenWriteAsync(uri, "POST");
}
}
Server Code
public class FileController : Controller
{
[HttpPost]
public ActionResult Upload()
{
string filename = Server.MapPath("/Uploads/" + Path.GetRandomFileName();
try
{
using (FileStream fs = new FileStream(filename), FileMode.Create))
{
using (BinaryWriter bw = new BinaryWriter(fs))
{
using (BinaryReader br = new BinaryReader(Request.InputStream))
{
long bCount = 0;
long fileSize = br.BaseStream.Length;
const int BLOCK_SIZE = 4096;
byte[] bytes = new byte[BLOCK_SIZE];
do
{
bytes = br.ReadBytes(BLOCK_SIZE);
bCount += bytes.Length;
bw.Write(bytes);
} while (bCount < fileSize);
}
}
}
return Json(new { Result = "Complete" });
}
catch (Exception ex)
{
return Json(new { Result = "Error", Message = ex.Message });
}
}
}
Note that I'm using ASP.NET MVC to receive my file, but you should be able to use the same, core logic with WebForms.
/chris

Categories