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
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.
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.
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.
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
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