Using FtpWebRequest to find subfolder of FTP server [duplicate] - c#

This question already has answers here:
How to check if an FTP directory exists
(11 answers)
Closed 4 years ago.
I am using FTP to upload files to a folder on an FTP server folder, but first I need to determine that the folder exists. MSDN contains an example of how to use FtpWebResponse to check if a folder exists:
public class WebRequestGetExample
{
public static void Main ()
{
// Get the object used to communicate with the server.
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://www.contoso.com/");
request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
// This example assumes the FTP site uses anonymous logon.
request.Credentials = new NetworkCredential ("anonymous","janeDoe#contoso.com");
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
Console.WriteLine(reader.ReadToEnd());
Console.WriteLine("Directory List Complete, status {0}", response.StatusDescription);
reader.Close();
response.Close();
}
}
Using the code above, one can obtain a list of folders off the root level of the server, and I can do this in my own situation. That is NOT my question.
My question is, what if the folder I am wanting to write to is a SUBFOLDER of one of the folders that results from the call to ListDirectoryDetails? How do I dig deeper into the folder structure?

You can try this:
try
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://address/subfolder/subfolder");
request.Method = WebRequestMethods.Ftp.ListDirectory;
using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
{
// Directory exists, you can work on it.
}
}
catch (WebException ex)
{
if (ex.Response != null)
{
FtpWebResponse response = (FtpWebResponse)ex.Response;
if (response.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
{
// Directory not found.
}
}
}
This way, you are basically checking if you can list the directory by calling Ftp.ListDirectory as an FTP request method. If it fails, then your directory does not exist.

Let's say you want to use the subfolder temp. Then you have to append the folder to your URI like this:
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://www.contoso.com/temp/somefile.xyz");
In this way you can access subfolders, subsubfolders and so on.

Related

FtpWebRequest returning "550 File unavailable (e.g. file not found, no access)" when using ListDirectoryDetails for a directory that exists

I have an annoying problem preventing me to get a file I need in an FTP. This file may have differents names so I need to access the folder first and list files inside to do a request directly to the file then.
My problem is that I can access this file in Filezilla for example, and perfectly discovers the folder as well, but when using an FtpWebResponse instance to get the folder, I have an error 550
550 File unavailable (e.g. file not found, no access)
here is the code :
FtpWebRequest wr = (FtpWebRequest)WebRequest.Create("ftp://ftp.dachser.com/data/edi/kunden/da46168958/out");
wr.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
wr.Credentials = new NetworkCredential("login", "password");
FtpWebResponse response = (FtpWebResponse)wr.GetResponse();
Stream reponseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(reponseStream);
string names = reader.ReadToEnd();
FtpWebResponse response = (FtpWebResponse)wr.GetResponse();
is the line throwing the error
PS: Production, tests and FileZilla are on the same domain, using the same internet connection (if it helps)
Thanks for your attention and feedback
The FileZilla logs:
Logs from my program, error circled in red isn't related to FTP error
When FtpWebRequest interprets the URL, it does not consider the slash that separates the hostname and the path as a part of the path. The extracted path is then used with FTP CWD command as is. That means that the FTP server will resolve the path relatively to your home directory. If your account is not chrooted (the home is not seen as the root by the client), the lack of the leading slash leads to unexpected behaviour.
In your case, you start in /remote/path and with URL like ftp://example.com/remote/path/, it will try to change to remote/path, so ultimately to /remote/path/remote/path. That's not what you want.
Either you must use a relative path to the home folder. What in your case means using an URL without any path.
Or use an absolute path, for which you need to use two slashes after the hostname: ftp://example.com//remote/path/.
Also note that an URL to a folder should end with a slash: Why does FtpWebRequest return an empty stream for this existing directory?
For other 550 problems, see FtpWebRequest returns error 550 File unavailable
In 2021 this works on both our Linux and Windows live boxes reading from ftp server (both on Windows and Linux)
Note
the main folder on the Windows ftp is web
the main folder on the Linux ftp is public_html
TL;DR;
bottom line: the URL needs to be ended with /
It works:
ftp://ftp.yourdomain.com.br/public_html/
ftp://ftp.yourdomain.com.br//public_html/
ftp://ftp.yourdomain.com.br/web/
ftp://ftp.yourdomain.com.br//web/
It doesn't work:
ftp://ftp.yourdomain.com.br/public_html
ftp://ftp.yourdomain.com.br//public_html
ftp://ftp.yourdomain.com.br/web
ftp://ftp.yourdomain.com.br//web
Usage:
//verifiy if the directory public_html does exists
var url = "/public_html/";
var result = FtpUtil.DoesDirectoryExists(url, "ftp://ftp.yourdomain.com.br", "ftp user here", "ftp password here");
static bool DoesDirectoryExists(string directory, string ftpHost, string ftpUser, string ftpPassword) {
FtpWebRequest ftpRequest = null;
try {
ftpRequest = (FtpWebRequest)WebRequest.Create(new Uri("ftp://" + ftpHost + directory));
ftpRequest.Credentials = new NetworkCredential(ftpUser, string ftpPassword);
ftpRequest.UseBinary = true;// optional
ftpRequest.KeepAlive = false;// optional
ftpRequest.UsePassive = true;// optional
ftpRequest.Method = WebRequestMethods.Ftp.ListDirectory;
using (FtpWebResponse response = (FtpWebResponse)ftpRequest.GetResponse()) {
return true;//directory found
}
}
catch (WebException ex) {
if (ex.Response != null) {
FtpWebResponse response = (FtpWebResponse)ex.Response;
if (response.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
return false;// directory not found.
}
return false; // directory not found.
}
finally {
ftpRequest = null;
}
}

Fill ComboBox with names of files from a directory on FTP server

I have a file folder in my FTP server and I want to fill a ComboBox with the contents inside of that folder. How would I go about doing this?
string result = string.Empty;
//Request location and server name---------->
FtpWebRequest request =
(FtpWebRequest)WebRequest.Create("ftp://*******" +"/" + "Products" + "/");
//Lists directory
request.Method = WebRequestMethods.Ftp.ListDirectory;
// set credentials
request.Credentials = new NetworkCredential("user1","1234");
//initialize response
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
//reader to read response
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
combobox1.Text = FTP_Server();
//data from file.
result = reader.ReadToEnd();
reader.Close();
response.Close();
Thanks! I didn't know if this was even possible!
Read the listing by lines:
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://example.com/remote/path/");
request.Method = WebRequestMethods.Ftp.ListDirectory;
request.Credentials = new NetworkCredential("username", "password");
comboBox1.BeginUpdate();
try
{
using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
while (!reader.EndOfStream)
{
comboBox1.Items.Add(reader.ReadLine());
}
}
}
finally
{
comboBox1.EndUpdate();
}
Downloading whole listing to a string and splitting it afterwards (as suggested by the other answer) can be pretty ineffective, if there's lot of entries.
Without knowing the exact format of your response string, my instinct would be to split the response string:
string files[] = result.Split("\r\n");
Then to iterate over the individual files, adding them to your combobox1's Items:
// Depending on how many items you're adding, you may wish to prevent a repaint until the operation is finished
combobox1.BeginUpdate();
foreach(string file in files)
{
combobox1.Items.Add(file);
}
combobox1.EndUpdate();
That should take care of it for you! There is some excellent (and exhaustive) documentation on MSDN as well, which will often contain some usage examples to help you out further: https://msdn.microsoft.com/en-us/library/system.windows.forms.combobox(v=vs.110).aspx#Examples
Note that, if you end up wanting to display information from a different FTP response, you'll have to clear the combobox1 like so first: combobox1.Items.Clear();

c# Upload to ftp with not created directorys on ftp server

This is the path I am trying to upload to the ftp server:
_ftp://ftp-server/products/productxx/versionxx/releasexx/delivery/data.zip
The problem is that the folders "productxx/versionxx/releasexx/delivery/" do not exist on the server.
Can I create them automatically while uploading the .zip file in c#
My coding at the moment is:
FtpWebRequest request =
(FtpWebRequest)WebRequest.Create(pathToFtp);
// Method set to UploadFile
request.Method = WebRequestMethods.Ftp.UploadFile;
// set password and username
request.Credentials = new NetworkCredential(UserName, Password);
// write MemoryStream in ftpStream
using (Stream ftpStream = request.GetRequestStream())
{
memoryStream.CopyTo(ftpStream);
}
I am getting the System.Net.WebException: "Can't connect to FTP: (553) File name not allowed" at "using (Stream ftpStream =request.GetRequestStream())"
but if my pathToFtp is _ftp://ftp-server/products/data.zip it´s working well
One of the request methods available is WebRequestMethods.Ftp.MakeDirectory. You should be able to use that to do what you want.
Something like this (though I've not tested it), should do the trick:
async Task CreateDirectory(string path)
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(path);
request.Method = WebRequestMethods.Ftp.MakeDirectory;
using (var response = (FtpWebResponse)(await request.GetResponseAsync()))
{
Console.WriteLine($"Created: {path}");
}
}
It's answered in more detail here How do I create a directory on ftp server using C#?

Check if list of files exist on FTP server

I'm looking for a way, if possible, to connect to an ftp server, and then iterate through a list of local files to check their existence on the server. Now, I've found:
var request = (FtpWebRequest)WebRequest.Create("ftp://ftp.domain.com/doesntexist.txt");
request.Credentials = new NetworkCredential("user", "pass");
request.Method = WebRequestMethods.Ftp.GetFileSize;
try
{
var response = (FtpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
var response = (FtpWebResponse)ex.Response;
if (response.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
{
//Does not exist
}
}
But, if I read this right (I haven't had my coffee yet), it creates a WebRequest for each file. The overall goal is to check if these files exist, and if not, upload them. My question is, do I HAVE to do this individually, or is it possible(or even feasible) to just connect to the FTP once and then do my check/uploads?
1) Get a list of files from FTP as described here
2) Get a list of local files using Directory.GetFiles()
3) loop through one list and check if the other list contains the item

Get Binary File List from Remote server

I'm developing a system that need to download binary files from a server folder. In here I will check before downloading whether they are in my local folder.so I need to get list of the *.bin files.
I have tried code in below, but it generate list all the files that on server folder.
private string[] GetRemoteFileList()
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(new Uri(_remoteHost));
request.Credentials = new NetworkCredential(_remoteUser, _remotePass);
request.Method = WebRequestMethods.Ftp.ListDirectory;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
string FileNames = reader.ReadToEnd();
string[] Files = Regex.Split(FileNames, "\r\n");
return Files;
}
What I need is filter out only *.bin files. How can I achieve this?
What have you tried?
You have now in Files an array of all files in the current directory. Why don't you filter that list? For example:
return Files.Where(
f => f.EndsWith(".bin", StringComparison.OrdinalIgnoreCase)
).ToList();

Categories

Resources