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);
}
}
Related
I have an issue sending big file to an FTP site and I would like to check the file size after the transfer (sometimes it works sometimes it fails). The transfer is within an SSIS and I'm using Dts.Connections in C#.
My code:
public long TransferFile(string file)
{
long filesize = 0L;
try
{
string[] newfile = new[] { file };
ConnectionManager ftpCM = Dts.Connections["ftp_server"];
string remoteDir = Dts.Variables["FtpWorkingDirectory"].Value.ToString();
FtpClientConnection ftpClient = new FtpClientConnection(ftpCM.AcquireConnection(null));
ftpClient.UsePassiveMode = true;
ftpClient.Connect();
ftpClient.Retries = 10;
ftpClient.SetWorkingDirectory(remoteDir);
ftpClient.SendFiles(newfile, remoteDir, true, false);
ftpClient.Close();
}
catch (Exception ex)
{
throw ex;
}
return filesize;
}
I found examples using FtpWebRequest but I don't have the ftp uri available so I don't see how to use this method. How can I get this file size?
UPDATE:
Adding this:
FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + ftpCM.ConnectionString + remoteDir + "/" + file));
request.Proxy = null;
DtsProperty ServerUsername = ftpCM.Properties["ServerUserName"];
DtsProperty ServerPassword = ftpCM.Properties["ServerPassword"];
request.Credentials = new NetworkCredential(ServerUsername.GetValue(ftpCM).ToString(), ServerPassword.GetValue(ftpCM).ToString());
request.Method = WebRequestMethods.Ftp.GetFileSize;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
filesize = response.ContentLength;
response.Close();
I get error: The property ServerPassword is write-only.
The final solution was to store the username and password in Variables instead of connection parameters.
And with the following code:
public long TransferFile(string file)
{
long filesize = 0L;
try
{
string[] newfile = new[] { file };
ConnectionManager ftpCM = Dts.Connections["ftp_server"];
string remoteDir = Dts.Variables["FtpWorkingDirectory"].Value.ToString();
string ServerUsername = Dts.Variables["ServerUsername"].Value.ToString();
string ServerPassword = Dts.Variables["ServerPassword"].Value.ToString();
FtpClientConnection ftpClient = new FtpClientConnection(ftpCM.AcquireConnection(null));
ftpClient.UsePassiveMode = true;
ftpClient.ServerUserName = ServerUsername;
ftpClient.ServerPassword = ServerPassword;
ftpClient.Connect();
ftpClient.Retries = 10;
ftpClient.SetWorkingDirectory(remoteDir);
ftpClient.SendFiles(newfile, remoteDir, true, false);
ftpClient.Close();
FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + ftpCM.ConnectionString + remoteDir + "/" + Path.GetFileName(file)));
request.Proxy = null;
request.Credentials = new NetworkCredential(ServerUsername, ServerPassword);
request.Method = WebRequestMethods.Ftp.GetFileSize;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
filesize = response.ContentLength;
response.Close();
}
catch (Exception ex)
{
throw ex;
}
return filesize;
}
I am trying to create an auto update for an application however I am having a bit of trouble with the updating part. Basically what I have is a windows service that periodically checks for updates and when it finds and update it launches a console application to update itself. The code for the console application is below.
The problem I'm having is that when I uninstall the service and replace the file that drives the service, I get a system.badimageformat exception. Despite reinstalling an identical file. If I uninstall and re-install the file without downloading it and replacing it from FTP there is no issue, but as soon as I change the file it starts giving me exceptions. Does anyone have any ideas on how I can work around this error. I am confident its not a 32 vs 64 bit issue which is what commonly causes this error.
static void Main(string[] args)
{
if (!System.Diagnostics.EventLog.SourceExists("OCR Updater"))
{
EventLog.CreateEventSource("OCR Updater", "Application");
}
ServiceController sc = new ServiceController("OCR Scheduler", ".");
if (sc.Status == ServiceControllerStatus.Running)
{
sc.Stop();
sc.WaitForStatus(ServiceControllerStatus.Stopped);
}
ProcessStartInfo Uninstallpsi = new ProcessStartInfo();
Uninstallpsi.Verb = "runas";
Uninstallpsi.UseShellExecute = false;
Uninstallpsi.FileName = AppDomain.CurrentDomain.BaseDirectory.ToString() + "installutil.exe";
Uninstallpsi.Arguments = " /u " + "\"" + AppDomain.CurrentDomain.BaseDirectory.ToString() + "OCR_Scheduler_Service.exe\"";
Process.Start(Uninstallpsi);
Console.WriteLine("Sleeping Thread after uninstall");
System.Threading.Thread.Sleep(10000);
OCRUpdater program = new OCRUpdater();
List<string> Files = program.GetFiles();
foreach (string item in Files)
{
if (item.ToString() == "Sqlite" || item.ToString() == "License.xml")
{
continue;
}
// Get the object used to communicate with the server.
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://ftp.mccinnovations.com/OCR_Scheduler/V2Updates/Files/" + item);
request.Method = WebRequestMethods.Ftp.DownloadFile;
// This example assumes the FTP site uses anonymous logon.
request.Credentials = new NetworkCredential("ftp admin", "_Stingray_12");
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
string[] temp = reader.ReadToEnd().Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
reader.Close();
response.Close();
string DesktopFile = "";
try
{
DesktopFile = #"C:\Users\hnelson\Desktop\" + item;
if (File.Exists(DesktopFile))
{
File.Delete(DesktopFile);
}
File.WriteAllLines(DesktopFile, temp);
}
catch (Exception ex)
{
EventLog.WriteEntry("OCR Updater", "Error in file path" + DesktopFile + ex.Message);
continue;
}
try
{
File.Delete(#"C:\Program Files (x86)\MCCi\OCR Scheduler V2\" + item);
System.Threading.Thread.Sleep(2000);
File.Copy(DesktopFile, #"C:\Program Files (x86)\MCCi\OCR Scheduler V2\" + item, true);
File.Delete(DesktopFile);
EventLog.WriteEntry("OCR Updater", DesktopFile);
}
catch (Exception)
{
EventLog.WriteEntry("OCR Updater", DesktopFile);
EventLog.WriteEntry("OCR Updater", "Error in file path " + #"C:\Program Files (x86)\MCCi\OCR Scheduler V2\" + item);
continue;
}
}
try
{
System.Threading.Thread.Sleep(5000);
ProcessStartInfo psi = new ProcessStartInfo();
psi.Verb = "runas";
psi.UseShellExecute = false;
psi.FileName = AppDomain.CurrentDomain.BaseDirectory.ToString() + "installutil.exe";
psi.Arguments = " " + "\"" + AppDomain.CurrentDomain.BaseDirectory.ToString() + "OCR_Scheduler_Service.exe\"";
Process.Start(psi);
}
catch (Exception ex)
{
EventLog.WriteEntry("OCR Updater", "Could not reinstall service" + ex.Message + ex.InnerException);
}
System.Threading.Thread.Sleep(10000);
Console.WriteLine("Finished resinstalling the service.");
try
{
string[] serviceStartArgs = { "true" };
sc.Start(serviceStartArgs);
sc.WaitForStatus(ServiceControllerStatus.Running);
}
catch (Exception ex)
{
EventLog.WriteEntry("OCR Updater", "Could not start the service after install" + " " + ex.Message + ex.InnerException);
}
}
public List<string> GetFiles()
{
// Get the object used to communicate with the server.
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://ftp.mccinnovations.com/OCR_Scheduler/V2Updates/Files/");
request.Method = WebRequestMethods.Ftp.ListDirectory;
// This example assumes the FTP site uses anonymous logon.
request.Credentials = new NetworkCredential("ftp admin", "_Stingray_12");
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
List<string> Files = new List<string>();
while (reader.EndOfStream == false)
{
Files.Add(reader.ReadLine());
}
reader.Close();
response.Close();
return Files;
}
}
}
The main problem is that you treat the files as text files:
string[] temp = reader.ReadToEnd().Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
....
File.WriteAllLines(DesktopFile, temp);
You can use this instead:
Stream responseStream = response.GetResponseStream();
...
using (FileStream destStream = File.Create(DesktopFile))
{
responseStream.CopyTo(destStream);
}
responseStream.Close();
response.Close();
However, this is still not the best solution, since you should use the pattern
using (X123 x123 = new X123(y))
{
// do something with x123
}
for all classes which support IDisposable.
In addition, I have some concerns about using Sleep() in so many situations. This is seldom a good idea.
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.
I have created a function that find files on a FTP folder.
public static List<string> GetFileList(NetworkCredential credential, string FTPSite, string FTPFolder, string extension)
{
string LSOutput = "";
List<string> files = new List<string>();
//Fetch LS
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(#"ftp://" + FTPSite + FTPFolder);
request.Credentials = credential;
request.UseBinary = true;
request.EnableSsl = true;
request.Method = WebRequestMethods.Ftp.ListDirectory;
FtpWebResponse response = null;
response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
LSOutput = reader.ReadToEnd();
reader.Close();
response.Close();
PrepareLog("LS output while finding files:");
PrepareLog(LSOutput);
//Parse the LS
string[] LSOutputLines = LSOutput.Trim().Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
foreach (string LSOutputLine in LSOutputLines)
files.Add(LSOutputLine);
//Filter files
files = files.Where(f => f.ToLower().EndsWith(extension.ToLower())).ToList();
PrepareLogAndEmail("Total " + extension.ToLower() + " files found: " + files.Count, LogMessageType.Simple);
return files;
}
Exception handling is done at the place where the function is being called.
Now the problem is that sometimes the FTP faces some issues(like timeout) and then we have to rerun the program.
I have been asked to add 3 times retry mechanism and here is what I did to retry it once.
public static List<string> GetFileList(NetworkCredential credential, string FTPSite, string FTPFolder, string extension)
{
string LSOutput = "";
List<string> files = new List<string>();
try
{
//Fetch LS
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(#"ftp://" + FTPSite + FTPFolder);
request.Credentials = credential;
request.UseBinary = true;
request.EnableSsl = true;
request.Method = WebRequestMethods.Ftp.ListDirectory;
FtpWebResponse response = null;
response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
LSOutput = reader.ReadToEnd();
reader.Close();
response.Close();
PrepareLog("LS output while finding files:");
PrepareLog(LSOutput);
}
catch (Exception ex)
{
PrepareLogAndEmail("First attempt failed: Details: " + ex.Message, LogMessageType.AttemptFailed);
PrepareLogAndEmail("Second attempt started" + ex.Message, LogMessageType.Simple);
//Fetch LS
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(#"ftp://" + FTPSite + FTPFolder);
request.Credentials = credential;
request.UseBinary = true;
request.EnableSsl = true;
request.Method = WebRequestMethods.Ftp.ListDirectory;
FtpWebResponse response = null;
response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
LSOutput = reader.ReadToEnd();
reader.Close();
response.Close();
PrepareLog("LS output while finding files(second attempt):");
PrepareLog(LSOutput);
}
//Parse the LS
string[] LSOutputLines = LSOutput.Trim().Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
foreach (string LSOutputLine in LSOutputLines)
files.Add(LSOutputLine);
//Filter files
files = files.Where(f => f.ToLower().EndsWith(extension.ToLower())).ToList();
PrepareLogAndEmail("Total " + extension.ToLower() + " files found: " + files.Count, LogMessageType.Simple);
return files;
}
Now if I have to add 2 more tries, will I need to do this sort of daiys chaining or is there any other cleaner option available ?
I would go with a retry loop, something like below
You will notice that I make use of a bolean to flag out of a successfull download, or the retries count to terminate.
I would even go as far as changing the last section to check if the download was successfull, and notify the user if it was not, Maybe even logging the error messages.
public static List<string> GetFileList(NetworkCredential credential, string FTPSite, string FTPFolder, string extension)
{
List<string> files = new List<string>();
int retries = 0;
int maxRetries = 5;
bool downloaded = false;
string LSOutput = "";
while (!downloaded && retries < maxRetries)
{
try
{
LSOutput = "";
//Fetch LS
FtpWebRequest request = (FtpWebRequest) WebRequest.Create(#"ftp://" + FTPSite + FTPFolder);
request.Credentials = credential;
request.UseBinary = true;
request.EnableSsl = true;
request.Method = WebRequestMethods.Ftp.ListDirectory;
FtpWebResponse response = null;
response = (FtpWebResponse) request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
LSOutput = reader.ReadToEnd();
reader.Close();
response.Close();
PrepareLog("LS output while finding files:");
PrepareLog(LSOutput);
downloaded = true;
}
catch (Exception ex)
{
retries++;
}
}
if (downloaded)
{
//Parse the LS
string[] LSOutputLines = LSOutput.Trim().Split(new string[] {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries);
foreach (string LSOutputLine in LSOutputLines)
files.Add(LSOutputLine);
//Filter files
files = files.Where(f => f.ToLower().EndsWith(extension.ToLower())).ToList();
PrepareLogAndEmail("Total " + extension.ToLower() + " files found: " + files.Count, LogMessageType.Simple);
return files;
}
else
{
PrepareLogAndEmail("Failed to download file", LogMessageType.Simple);
return null;
}
}
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");
}
}