I have this code which works perfect when there is a file on FTP site , but when there is no file on FTP site it fails.
The error II get is in foreach (string file in files) and it says there is null reference .
How can I fix this so that if there is no file on FTP site this code will work.
Thanks in advance.
my error message
System.NullReferenceException was unhandled by user code
code
public void Main()
{
String[] files = GetFileList();
foreach (string file in files)
{
Download(file);
}
}
public string[] GetFileList()
{
string[] downloadFiles;
StringBuilder result = new StringBuilder();
WebResponse response = null;
StreamReader reader = null;
try
{
//FtpWebRequest reqFTP;
WebRequest reqFTP;
reqFTP = (FtpWebRequest)WebRequest.Create(new Uri("ftp://" + Dts.Variables["strHost"].Value+"/"));
//reqFTP.UseBinary = true;
String FTPUser = (String)Dts.Variables["strUserName"].Value;
String FTPPwd = (String)Dts.Variables["strPassword"].Value;
reqFTP.Credentials = new NetworkCredential(FTPUser, FTPPwd);
reqFTP.Method = WebRequestMethods.Ftp.ListDirectory;
reqFTP.Proxy = null;
//reqFTP.KeepAlive = true;
//reqFTP.UsePassive = true;
response = reqFTP.GetResponse();
reader = new StreamReader(response.GetResponseStream());
string line = reader.ReadLine();
while (line != null)
{
result.Append(line);
result.Append("\n");
line = reader.ReadLine();
}
// to remove the trailing '\n'
result.Remove(result.ToString().LastIndexOf('\n'), 1);
return result.ToString().Split('\n');
}
catch (Exception ex)
{
if (reader != null)
{
reader.Close();
}
if (response != null)
{
response.Close();
}
downloadFiles = null;
return downloadFiles;
}
}
private void Download(string file)
{
try
{
string uri = "ftp://" + Dts.Variables["strHost"].Value + "/" + file;
Uri serverUri = new Uri(uri);
if (serverUri.Scheme != Uri.UriSchemeFtp)
{
return;
}
WebRequest reqFTP;
//FtpWebRequest reqFTP;
reqFTP = (FtpWebRequest)WebRequest.Create(new Uri("ftp://" + Dts.Variables["strHost"].Value + "/" + file));
String FTPUser = (String)Dts.Variables["strUserName"].Value;
String FTPPwd = (String)Dts.Variables["strPassword"].Value;
reqFTP.Credentials = new NetworkCredential(FTPUser, FTPPwd);
//reqFTP.KeepAlive = true;
reqFTP.Method = WebRequestMethods.Ftp.DownloadFile;
//reqFTP.UseBinary = true;
reqFTP.Proxy = null;
//reqFTP.UsePassive = false;
FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
Stream responseStream = response.GetResponseStream();
FileStream writeStream = new FileStream(Dts.Variables["strLocalFolder"].Value + "\\" + file, FileMode.Create); int Length = 2048;
Byte[] buffer = new Byte[Length];
int bytesRead = responseStream.Read(buffer, 0, Length);
while (bytesRead > 0)
{
writeStream.Write(buffer, 0, bytesRead);
bytesRead = responseStream.Read(buffer, 0, Length);
}
writeStream.Close();
response.Close();
}
catch (WebException wEx)
{
MessageBox.Show(wEx.Message, "Download Error");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Download Error");
}
}
You need to test the result of GetFilesList() for null, because you return null in case an error (in catch clause of GetFileList() you set the result - downloadFiles - to null).
public void Main()
{
String[] files = GetFileList();
if (files != null) // add this line
{
foreach (string file in files)
{
Download(file);
}
}
Problem is your call to GetFileList returns null and thus the foreach fails.
Related
Failed to get response for large file HTTP put create file using c#
I am using file watcher service service monitor, when user created file or folder we are uploading to cloud
if file size more than 512 MB it is taking too much time to get the response
here I am confusing here the issue with my code or server
and reason for this error
if any changes on my code suggest me.
{
var fileFolderObj1 = new FileFolder();
var postURL = apiBaseUri + "/filefolder/create/file/user/" + userId; // +"?type=file";
code = HttpStatusCode.OK;
HttpWebResponse response = null;
FileInfo f = new FileInfo(filePath);
long filesizeF = f.Length;
try
{
string selectedFile = null;
selectedFile = filePath;
var fi = System.IO.Path.GetFileName(filePath);
////commented for some reason
var postParameters = new Dictionary<string, object>();
postParameters.Add("file", new FileParameter(filePath, ""));
postParameters.Add("parentId", parentId);
postParameters.Add("newName", fi);
postParameters.Add("cloudId", cloudId);
postParameters.Add("isSecure", isSecure);
//postParameters.Add("fileSize", fi.Length);
postParameters.Add("fileSize", filesizeF);
var userAgent = "Desktop";
var formDataBoundary = "----WebKitFormBoundary" + DateTime.Now.Ticks.ToString("x");
var uri = new Uri(postURL);
var createFileRequest = WebRequest.Create(uri) as HttpWebRequest;
this.SetBasicAuthHeader(createFileRequest, userId, password);
createFileRequest.ContentType = "multipart/form-data";
createFileRequest.Method = "PUT";
createFileRequest.Timeout = System.Threading.Timeout.Infinite;
createFileRequest.KeepAlive = false;/*true;*/
createFileRequest.UserAgent = userAgent;
createFileRequest.CookieContainer = new CookieContainer();
try
{
using (var requestStream = createFileRequest.GetRequestStream())
{
}
using (response = (HttpWebResponse)createFileRequest.GetResponse())
{
StreamReader(response.GetResponseStream()).ReadToEnd();
fileFolderObj1 = JsonConvert.DeserializeObject<FileFolder>(reslut);
}
}
catch (Exception exc)
{
if (response != null)
{
code = response.StatusCode;
}
}
}
catch (Exception exc)
{
}
}
}
private static readonly Encoding encoding = Encoding.UTF8;
private void WriteMultipartFormData(Dictionary<string, object> postParameters, string boundary, Stream requestStream, ILogService logService = null)
{
var needsCLRF = false;
foreach (var param in postParameters)
{
// Skip it on the first parameter, add it to subsequent parameters.
if (needsCLRF)
{
requestStream.Write(encoding.GetBytes("\r\n"), 0, encoding.GetByteCount("\r\n"));
}
needsCLRF = true;
if (param.Value is FileParameter)
{
var fileToUpload = (FileParameter)param.Value;
// Add just the first part of this param, since we will write the file data directly to the Stream
var header = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n",
boundary,
param.Key,
fileToUpload.FileName ?? param.Key,
fileToUpload.ContentType ?? "application/octet-stream");
requestStream.Write(encoding.GetBytes(header), 0, encoding.GetByteCount(header));
// Write the file data directly to the Stream, rather than serializing it to a string.
FileStream fileStream = new FileStream(fileToUpload.FileName, FileMode.Open, FileAccess.Read);
byte[] buffer = new byte[4096];
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0,buffer.Length)) != 0)
{
requestStream.Write(buffer, 0, bytesRead);
logService.Debug("WRITEMULTIPART FORM DATA Bufferlent Running :{0}", bytesRead);
}
fileStream.Close();
}
else
{
var postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}",
boundary,
param.Key,
param.Value);
requestStream.Write(encoding.GetBytes(postData), 0, encoding.GetByteCount(postData));
}
}
// Add the end of the request. Start with a newline
var footer = "\r\n--" + boundary + "--\r\n";
requestStream.Write(encoding.GetBytes(footer), 0, encoding.GetByteCount(footer));
}
}
I try to "create" a recursive method, which copy the ftp directory list to a treeView.
I allready tried to do that, but it is more quick & dirty as clean & simple.
Here you can see my Code-Snippets:
public void connectToServer(string pServerIP, string pServerPort, string pUsername, string pPassword)
{
_serverIP = pServerIP;
_serverPort = pServerPort;
_username = pUsername;
_password = pPassword;
string ftpServerPath = "ftp://" + pServerIP + ":" + pServerPort + "/";
try
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpServerPath);
request.Method = WebRequestMethods.Ftp.ListDirectory;
request.Credentials = new NetworkCredential(pUsername, pPassword);
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
secondLevelDirectotyList = new List<string>();
int i = 0;
TreeNode rootTreeNode = tVDirectories.Nodes.Add("/");
Console.WriteLine("/\n");
while (!reader.EndOfStream)
{
secondLevelDirectotyList.Add(reader.ReadLine());
Console.WriteLine("...: " + secondLevelDirectotyList[i]);
i++;
}
reader.Close();
response.Close();
getFTPDirectoryList(secondLevelDirectotyList, 0);
}
catch (WebException ex)
{
MessageBox.Show("The following Exceptions occurs:\n" + ex.Message, "Exception occurs", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void getFTPDirectoryList(List<string> pTopLevelDirectoryList, int pDirectoryListIndexer)//string pFTPPath)
{
//List<string>
string ftpServerPath = "ftp://" + _serverIP + ":" + _serverPort + "/" + pTopLevelDirectoryList[pDirectoryListIndexer];//pFTPPath;
try
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpServerPath);
request.Method = WebRequestMethods.Ftp.ListDirectory;
request.Credentials = new NetworkCredential(_username, _password);
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
thirdLevelDirectoryList = new List<string>();
int i = 0;
TreeNode ftpServerDirectory = tVDirectories.Nodes[0].Nodes.Add(pTopLevelDirectoryList[pDirectoryListIndexer]);//pFTPPath);
while (!reader.EndOfStream)
{
string streamFTPPath = reader.ReadLine(); //Ließt die Zeile des Streams aus
thirdLevelDirectoryList.Add(streamFTPPath); //Fügt den gesamten Pfad in die String-Liste
Console.WriteLine("...........: " + thirdLevelDirectoryList[i]);
string newTreeNode = streamFTPPath.Substring(streamFTPPath.IndexOf(#"/") + 1);
ftpServerDirectory.Nodes.Add(newTreeNode); //Fügt nur den Unterordner- oder Unterdatei-Namen in die Ansicht ein
i++;
}
reader.Close();
response.Close();
//rekursiv
pDirectoryListIndexer++;
try
{
getFTPDirectoryList(pTopLevelDirectoryList, pDirectoryListIndexer);
}
catch (ArgumentOutOfRangeException ex)
{
// start next level Directory List
//pDirectoryListIndexer = 0;
//getFTPDirectoryList(thirdLevelDirectoryList, 0);
}
}
catch (WebException ex)
{
MessageBox.Show("The following Exceptions occurs:\n" + ex.Message, "Exception occurs", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
As you can see, I don't get the point to browse through the ftp folders.
You also may noticed that I work with ftp-protocol the early first time.
For example: I don't know whether I should open a request every time the ftp-ListDirectory-Command is send.
I want something like this:
root/
...folder1
......file1infolder1
...file2
...folder2
......file3infolder2
I hope you can understand me :D
and I am also sry for my bad english.
This is my solution for a recursive method, which list all files and folders from a ftp-path,
BUT
it is unefficient and it is impossible to use!!!!
If you only have five folders, this method will work, but if you have more than ~five folders the method won't end - sure it will be finished SOME DAY..
So for everyone, who read this:
Think about your Idea to use a recursive method to list the ftp-directory!
You better should send the NLIST-ftp-command once the user "opens" a folder.
private void FtpNlistRecursive(string pPath)
{
try
{
DirectoryListOfCurrent = new List<string>();
_ftpServerFullPath = "ftp://" + _serverIP + ":" + _serverPort + "/" + pPath;
string newItem = "";
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(_ftpServerFullPath);
request.Method = WebRequestMethods.Ftp.ListDirectory;
request.Credentials = new NetworkCredential(_username, _password);
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
while (!reader.EndOfStream)
{
newItem = reader.ReadLine();
string shortItem = pPath.Substring(pPath.IndexOf(#"/") + 1); // Aus "Ornder1/Datei1.txt" wird "Datei1.txt"
if (!shortItem.Equals(newItem))
{
try
{
if (pPath.Equals("/"))
{
DirectoryListOfCurrent.Add(newItem);
directoryListOfAll.Add(newItem);
}
else
{
string completePath = pPath + newItem.Substring(newItem.IndexOf(#"/"));
DirectoryListOfCurrent.Add(completePath);
directoryListOfAll.Add(completePath);
}
}
catch (ArgumentOutOfRangeException ex)
{
//bei ZB "Datei3.txt" gibt es kein "/", somit einfach ignorieren
}
}
}
reader.Close();
response.Close();
foreach (string item in DirectoryListOfCurrent)
{
FtpNlistRecursive(item);
}
}
catch (Exception ex)
{
ExceptionOccurs(ex);
}
}
I'm using the FTP function in c# in order to download somes files.
My problem is that the download is slow.
I don't have any problem with Filezilla, and my connection is OK.
I'm thinking about the FTP functions implementations, here is my code :
public static string DownloadFromList(string strParam,string filePath)
{
string[] FilesToDownload = strParam.Split('\n');
try
{
FtpWebRequest reqFTP;
foreach(string file in FilesToDownload)
{
string tmpfile = file;
if (tmpfile.Contains("\n"))
{
tmpfile = tmpfile.Replace('\n', ' ');
}
FileInfo fileToDownload = new FileInfo(tmpfile);
tmpfile = fileToDownload.Name;
FileStream outputStream = new FileStream(filePath.Trim() + "\\" + tmpfile.Trim(), FileMode.Create);
if (strDirectory.Trim() != "")
{
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + strHost.Trim() + "/" + strDirectory.Trim() + "/" + tmpfile.Trim()));
}
else
{
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + strHost.Trim() + "/" + tmpfile.Trim()));
}
reqFTP.ConnectionGroupName = "MyGroupName";
reqFTP.Method = WebRequestMethods.Ftp.DownloadFile;
reqFTP.UseBinary = true;
reqFTP.KeepAlive = true;
reqFTP.Timeout = -1;
reqFTP.Credentials = new NetworkCredential(strUser.Trim(), strPass.Trim());
FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
Stream ftpStream = response.GetResponseStream();
StreamReader reader = new StreamReader(ftpStream, System.Text.Encoding.UTF8);
long cl = response.ContentLength;
int bufferSize = 8192;
char[] bytesInStream = new char[8192];
int readCount;
StreamWriter sw = new StreamWriter(outputStream);
int len;
while ((len = reader.Read(bytesInStream, 0, bytesInStream.Length)) > 0)
{
sw.Write(bytesInStream, 0, len);
}
sw.Close();
outputStream.Close();
ftpStream.Close();
response.Close();
}
return "ok";
}
catch (Exception ex)
{
return (ex.Message);
}
}
Is it necessary to set useBinary = true ?
KeepAlive is setted to true in order to use the same connection, but is it true ?
Is it possible to set the credential only one time ?
How can i improve this please?
Thanks a lot :)
Best regards,
Hi and thanks for looking!
Background
I need to pull the file locations (path and filename) for all files at a given FTP address.
For files on a mapped network or local drive, this code would work:
foreach(string fileName f in Directory.GetFiles("C\\:SomeDirectory"), "*.*",
SearchOption.AllDirectories)
{
//do stuff with each file found
}
But this will NOT work over an FTP connection. I have already found this MS documentation which covers the establishing of an FTPWebRequest, but it does not show me how to loop through each file found (in all nested directories as well).
I am using C# within a forms app.
Question
How do I accomplish this:
foreach(string fileName f in Directory.GetFiles("C\\:SomeDirectory"), "*.*",
SearchOption.AllDirectories)
{
//do stuff with each file found
}
With an FTP connection?
Many thanks!!
UPDATE / Final Answer
Special thanks to #sunk for getting this going. I made a minor tweek to his code that makes it fully recursive so that it can drill into nested folders. Here is the final code:
//A list that holds all file locations in all folders of a given FTP address:
List<string> fnl= new List<string>();
//A string to hold the base FTP address:
string ftpBase = "ftp://[SOME FTP ADDRESS]";
//A button-click event. Can be a stand alone method as well
private void GetFileLocations(object sender, EventArgs e)
{
//Get the file names from the FTP location:
DownloadFileNames(ftpBase);
//Once 'DownloadFileNames' has run, we have populated 'fnl'
foreach(var f in fnl)
{
//do stuff
}
}
//Gets all files in a given FTP address. RECURSIVE METHOD:
public void DownloadFileNames(string ftpAddress)
{
string uri = ftpAddress;
FtpWebRequest reqFTP = (FtpWebRequest)FtpWebRequest.Create(uri);
reqFTP.Credentials = new NetworkCredential("pella", "PellaWA01!");
reqFTP.EnableSsl = false;
reqFTP.KeepAlive = false;
reqFTP.UseBinary = true;
reqFTP.UsePassive = true;
reqFTP.Method = WebRequestMethods.Ftp.ListDirectory;
FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
Stream responseStream = response.GetResponseStream();
List<string> files = new List<string>();
StreamReader reader = new StreamReader(responseStream);
while (!reader.EndOfStream)
files.Add(reader.ReadLine());
reader.Close();
responseStream.Dispose();
//Loop through the resulting file names.
foreach (var fileName in files)
{
var parentDirectory = "";
//If the filename has an extension, then it actually is
//a file and should be added to 'fnl'.
if (fileName.IndexOf(".") > 0)
{
fnl.Add(ftpAddress.Replace("ftp://pella.upload.akamai.com/140607/pella/", "http://media.pella.com/") + fileName);
}
else
{
//If the filename has no extension, then it is just a folder.
//Run this method again as a recursion of the original:
parentDirectory += fileName + "/";
try
{
DownloadFileNames(ftpAddress + parentDirectory);
}
catch (Exception)
{
//throw;
}
}
}
}
First of all, you have to get the files name local on your machine using FTPWebRequest.
WebRequestMethods.Ftp.ListDirectory;
then use foreach {};
Here is the code:-
public List<string> DownloadFileNames()
{
string uri = "ftp://" + ftpServerIP + "/";
FtpWebRequest reqFTP = (FtpWebRequest)FtpWebRequest.Create(uri);
reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
reqFTP.EnableSsl = true;
reqFTP.KeepAlive = false;
reqFTP.UseBinary = true;
reqFTP.UsePassive = Settings.UsePassive;
reqFTP.Method = WebRequestMethods.Ftp.ListDirectory;
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(AcceptAllCertifications);
FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
Stream responseStream = response.GetResponseStream();
List<string> files = new List<string>();
StreamReader reader = new StreamReader(responseStream);
while (!reader.EndOfStream)
files.Add(reader.ReadLine());
reader.Close();
responseStream.Dispose();
return files;
}
Now you have the List:-
List<string> FileNameList = DownloadFileNames();
foreach (var fileName in FileNameList)
{
}
the ListDirectoryDetails command used in the example just returns a string. You will have to manually parse it to build a list of files and subdirectories.
Found at http://social.msdn.microsoft.com/Forums/en/ncl/thread/079fb811-3c55-4959-85c4-677e4b20bea3
string[] files = GetFileList();
foreach (string file in files)
{
Download(file);
}
public string[] GetFileList()
{
string[] downloadFiles;
StringBuilder result = new StringBuilder();
WebResponse response = null;
StreamReader reader = null;
try
{
FtpWebRequest reqFTP;
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + ftpServerIP + "/"));
reqFTP.UseBinary = true;
reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
reqFTP.Method = WebRequestMethods.Ftp.ListDirectory;
reqFTP.Proxy = null;
reqFTP.KeepAlive = false;
reqFTP.UsePassive = false;
response = reqFTP.GetResponse();
reader = new StreamReader(response.GetResponseStream());
string line = reader.ReadLine();
while (line != null)
{
result.Append(line);
result.Append("\n");
line = reader.ReadLine();
}
// to remove the trailing '\n'
result.Remove(result.ToString().LastIndexOf('\n'), 1);
return result.ToString().Split('\n');
}
catch (Exception ex)
{
if (reader != null)
{
reader.Close();
}
if (response != null)
{
response.Close();
}
downloadFiles = null;
return downloadFiles;
}
}
private void Download(string file)
{
try
{
string uri = "ftp://" + ftpServerIP + "/" + remoteDir + "/" + file;
Uri serverUri = new Uri(uri);
if (serverUri.Scheme != Uri.UriSchemeFtp)
{
return;
}
FtpWebRequest reqFTP;
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + ftpServerIP + "/" + remoteDir + "/" + file));
reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
reqFTP.KeepAlive = false;
reqFTP.Method = WebRequestMethods.Ftp.DownloadFile;
reqFTP.UseBinary = true;
reqFTP.Proxy = null;
reqFTP.UsePassive = false;
FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
Stream responseStream = response.GetResponseStream();
FileStream writeStream = new FileStream(localDestnDir + "\" + file, FileMode.Create);
int Length = 2048;
Byte[] buffer = new Byte[Length];
int bytesRead = responseStream.Read(buffer, 0, Length);
while (bytesRead > 0)
{
writeStream.Write(buffer, 0, bytesRead);
bytesRead = responseStream.Read(buffer, 0, Length);
}
writeStream.Close();
response.Close();
}
catch (WebException wEx)
{
MessageBox.Show(wEx.Message, "Download Error");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Download Error");
}
}
I can download FTP files, but the download code does not have a resume facility and multi part files download. Because there are file larger than 500 MB, I can't download them continuously, because the connection gets closed and it starts download from beginning. I wanted my code a resume facility if it gets disconnected.
The code I am using is:
public string[] GetFileList()
{
string[] downloadFiles;
StringBuilder result = new StringBuilder();
FtpWebRequest reqFTP;
try
{
reqFTP = (FtpWebRequest)FtpWebRequest.Create(
new Uri("ftp://" + ftpServerIP + "/"));
reqFTP.UseBinary = true;
reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
reqFTP.Method = WebRequestMethods.Ftp.ListDirectory;
WebResponse response = reqFTP.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
//MessageBox.Show(reader.ReadToEnd());
string line = reader.ReadLine();
while (line != null)
{
result.Append(line);
result.Append("\n");
line = reader.ReadLine();
}
result.Remove(result.ToString().LastIndexOf('\n'), 1);
reader.Close();
response.Close();
//MessageBox.Show(response.StatusDescription);
return result.ToString().Split('\n');
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
downloadFiles = null;
return downloadFiles;
}
}
private void Download(string filePath, string fileName)
{
FtpWebRequest reqFTP;
try
{
//filePath = <<The full path where the file is to be created.>>,
//fileName = <<Name of the file to be created
// (Need not be the name of the file on FTP server).>>
FileStream outputStream =
new FileStream(filePath + "\\" + fileName, FileMode.Create);
reqFTP = (FtpWebRequest)FtpWebRequest.Create(
new Uri("ftp://" + ftpServerIP + "/" + fileName));
reqFTP.Method = WebRequestMethods.Ftp.DownloadFile;
reqFTP.UseBinary = true;
reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
Stream ftpStream = response.GetResponseStream();
long cl = response.ContentLength;
int bufferSize = 2048;
int readCount;
byte[] buffer = new byte[bufferSize];
readCount = ftpStream.Read(buffer, 0, bufferSize);
while (readCount > 0)
{
outputStream.Write(buffer, 0, readCount);
readCount = ftpStream.Read(buffer, 0, bufferSize);
}
ftpStream.Close();
outputStream.Close();
response.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Before you start downloading check for the existence of the file on the local filesystem. If it exists, then get the size and use that for the ContentOffset member of the FtpWebRequest object. This functionality may not be supported by the FTP server, though.
A native implementation of FTP download resumption using the FtpWebRequest:
bool resume = false;
do
{
try
{
FileMode mode = resume ? FileMode.Append : FileMode.Create;
resume = false;
using (Stream fileStream = File.Open(#"C:\local\path\file.dat", mode))
{
var url = "ftp://ftp.example.com/remote/path/file.dat";
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(url);
request.Credentials = new NetworkCredential("username", "password");
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.ContentOffset = fileStream.Position;
using (Stream ftpStream = request.GetResponse().GetResponseStream())
{
ftpStream.CopyTo(fileStream);
}
}
}
catch (WebException)
{
resume = true;
}
}
while (resume);
Or use an FTP library that can resume the transfer automatically.
For example WinSCP .NET assembly does. With it, a resumable download is as trivial as:
// Setup session options
var sessionOptions = new WinSCP.SessionOptions
{
Protocol = Protocol.Ftp,
HostName = "ftp.example.com",
UserName = "user",
Password = "mypassword"
};
using (var session = new Session())
{
// Connect
session.Open(sessionOptions);
// Resumable download
session.GetFileToDirectory("/home/user/file.zip", #"C:\path");
}
(I'm the author of WinSCP)