Check if list of files exist on FTP server - c#

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

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;
}
}

Using FtpWebRequest to find subfolder of FTP server [duplicate]

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.

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();

"The remote server returned an error: (401) Unauthorized" error when trying to upload a file

I found a lot of question about (401) Unauthorized error, but none of them explained to me how to diagnose the issue.
I created a new MVC ASP.net app to learn how to upload a file to a sharepoint folder. As of right now, I can't seem to be able to copy a file from
C:\testfolder\file.txt to
C:\testfolder\UploadedFiles
Here is the method that I made where I send in the source file path and the target folder:
//Flag to indicate whether file was uploaded successfuly or not
bool isUploaded = true;
try
{
// Create a PUT Web request to upload the file.
WebRequest request = WebRequest.Create(targetDocumentLibraryPath);
//Set credentials of the current security context
request.PreAuthenticate = true;
request.UseDefaultCredentials = true;
ICredentials credentials = new NetworkCredential( "Username", "password", "Domain"); //I used my username and password here
request.Credentials = credentials;
//request.Credentials = CredentialCache.DefaultCredentials;
request.Method = "PUT";
// Create buffer to transfer file
byte[] fileBuffer = new byte[1024];
// Write the contents of the local file to the request stream.
using (Stream stream = request.GetRequestStream())
{
//Load the content from local file to stream
using (FileStream fsWorkbook = File.Open(sourceFilePath, FileMode.Open, FileAccess.Read))
{
//Get the start point
int startBuffer = fsWorkbook.Read(fileBuffer, 0, fileBuffer.Length);
for (int i = startBuffer; i > 0; i = fsWorkbook.Read(fileBuffer, 0, fileBuffer.Length))
{
stream.Write(fileBuffer, 0, i);
}
}
}
// Perform the PUT request
WebResponse response = request.GetResponse();
//Close response
response.Close();
}
catch (Exception ex)
{
//Set the flag to indiacte failure in uploading
isUploaded = false; //The remote server returned an error: (401) Unauthorized.
}
//Return the final upload status
return isUploaded;
}
I tried the following:
Changing the permission of the folders to be able to write/read from them for all users.
Use other folder locations (SharePoint, local drive, network drive) to upload the file to.
Any idea on how to get this problem to work? Any prospective on how to debug the problem is also appreciated.
Update: It is probably being my account is set as the app pool account in IIS. I am still not sure what the issue is.
This wouldn't be something like the proxy settings would it?
Do you need to add the default proxy setting to your
WebRequest
Also do you need to add
<system.net>
<defaultProxy useDefaultCredentials="true" />
</system.net>
To your web config?
This may help.
How should I set the default proxy to use default credentials?
I decided to try another approach and use httpposted file and .saveAs() described here

FTP Check if file exist when Uploading and if it does rename it in C#

I have a question about Uploading to a FTP with C#.
What I want to do is if the file exists then I want to add like Copy or a 1 after the filename so it doesn't replace the file. Any Ideas?
var request = (FtpWebRequest)WebRequest.Create(""+destination+file);
request.Credentials = new NetworkCredential("", "");
request.Method = WebRequestMethods.Ftp.GetFileSize;
try
{
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
FtpWebResponse response = (FtpWebResponse)ex.Response;
if (response.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
{
}
}
It's not particularly elegant as I just threw it together, but I guess this is pretty much what you need?
You just want to keep trying your requests until you get a "ActionNotTakenFileUnavailable", so you know your filename is good, then just upload it.
string destination = "ftp://something.com/";
string file = "test.jpg";
string extention = Path.GetExtension(file);
string fileName = file.Remove(file.Length - extention.Length);
string fileNameCopy = fileName;
int attempt = 1;
while (!CheckFileExists(GetRequest(destination + "//" + fileNameCopy + extention)))
{
fileNameCopy = fileName + " (" + attempt.ToString() + ")";
attempt++;
}
// do your upload, we've got a name that's OK
}
private static FtpWebRequest GetRequest(string uriString)
{
var request = (FtpWebRequest)WebRequest.Create(uriString);
request.Credentials = new NetworkCredential("", "");
request.Method = WebRequestMethods.Ftp.GetFileSize;
return request;
}
private static bool checkFileExists(WebRequest request)
{
try
{
request.GetResponse();
return true;
}
catch
{
return false;
}
}
Edit: Updated so this will work for any type of web request and is a little slimmer.
Since FTP control protocol is slow in nature (send-receive) I suggest first pulling directory content and checking against it before uploading the file. Note that dir can return two different standards: dos and unix
Alternatively you can use the MDTM file command to check if file already exist (used to retrieve timestamp of a file).
There is no shortcut. You need to dir the target directory then use # to determine which name you want to use.
I am working on something similar. My problem was that:
request.Method = WebRequestMethods.Ftp.GetFileSize;
was not really working. Sometimes it gave exception sometimes it didn't. And for the same file! Have no idea why.
I change it as Tedd said (thank you, btw) to
request.Method = WebRequestMethods.Ftp.GetDateTimestamp;
and it seems to work now.

Categories

Resources