[ACCEPTED]-FileSystemWatcher for FTP-filesystemwatcher
You're going to have to implement a polling 6 solution, where you keep asking for the 5 directory content periodically. Compare 4 this to a cached list from the previous 3 call and determine what happened that way.
There's 2 nothing in the FTP protocol that will help 1 you with this unfortunately.
You cannot use the FileSystemWatcher
or any other way, because 17 the FTP protocol does not have any API to 16 notify a client about changes in the remote 15 directory.
All you can do is to periodically 14 iterate the remote tree and find changes.
It's 13 actually rather easy to implement, if you 12 use an FTP client library that supports 11 recursive listing of a remote tree. Unfortunately, the 10 built-in .NET FTP client, the FtpWebRequest
does not. But 9 for example with WinSCP .NET assembly, you can use the Session.EnumerateRemoteFiles
method.
See 8 the article Watching for changes in SFTP/FTP server:
// Setup session options
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Ftp,
HostName = "example.com",
UserName = "user",
Password = "password",
};
using (Session session = new Session())
{
// Connect
session.Open(sessionOptions);
List<string> prevFiles = null;
while (true)
{
// Collect file list
List<string> files =
session.EnumerateRemoteFiles(
"/remote/path", "*.*", EnumerationOptions.AllDirectories)
.Select(fileInfo => fileInfo.FullName)
.ToList();
if (prevFiles == null)
{
// In the first round, just print number of files found
Console.WriteLine("Found {0} files", files.Count);
}
else
{
// Then look for differences against the previous list
IEnumerable<string> added = files.Except(prevFiles);
if (added.Any())
{
Console.WriteLine("Added files:");
foreach (string path in added)
{
Console.WriteLine(path);
}
}
IEnumerable<string> removed = prevFiles.Except(files);
if (removed.Any())
{
Console.WriteLine("Removed files:");
foreach (string path in removed)
{
Console.WriteLine(path);
}
}
}
prevFiles = files;
Console.WriteLine("Sleeping 10s...");
Thread.Sleep(10000);
}
}
(I'm the author of WinSCP)
Though, if you actually want 7 to just download the changes, it's a way 6 easier. Just use the Session.SynchronizeDirectories
in the loop.
session.SynchronizeDirectories(
SynchronizationMode.Local, "/remote/path", @"C:\local\path", true).Check();
See the 5 article Keep local directory up to date (download changed files from remote SFTP/FTP server).
If you do not want to use a 3rd 4 party library, you have to do with limitations 3 of the FtpWebRequest
. For an example how to recursively 2 list a remote directory tree with the FtpWebRequest
, see 1 my answer to C# Download all files and subdirectories through FTP.
The FileSystemWatcher
class works by registering for events 18 with the host Windows operating system. As 17 such, it is limited to working on local 16 paths and UNC paths to directories hosted 15 on Windows systems. The MSDN documentation 14 on FileSystemWatcher
explains the paths which you can use 13 and some of the potential problems with 12 using the class.
If you are looking to be 11 alerted to changes on an FTP site, you will 10 have to use a polling mechanism to ask for 9 the current status of files or folders you 8 are interested in monitoring. You will be 7 able to see when files are added and removed 6 by comparing snapshots of the FTP site for 5 changes and raising similar events when 4 you detect changes. Unfortunately you wont 3 be able to detect rename events, but other 2 changes should be simple to monitor this 1 way.
Write a simple service to create FileSystemWatcher, pointing 5 at your ftp location.
Then when a file is 4 uploaded or modified, an event will be fired 3 in your service, which you can then use 2 to copy the file to your local machine.
File.Copy 1 etc.
Hav a look at: this blog
You can monitor the FTP location by following 1 method:
public class FtpFileSystemWatcher
{
public bool IsRunning
{
get;
private set;
}
public string FtpUserName
{
get;
set;
}
public string FtpPassword
{
get;
set;
}
public string FtpLocationToWatch
{
get;
set;
}
public string DownloadTo
{
get;
set;
}
public bool KeepOrignal
{
get;
set;
}
public bool OverwriteExisting
{
get;
set;
}
public int RecheckIntervalInSeconds
{
get;
set;
}
private bool DownloadInprogress
{
get;
set;
}
private System.Timers.Timer JobProcessor;
public FtpFileSystemWatcher(string FtpLocationToWatch = "", string DownloadTo = "", int RecheckIntervalInSeconds = 1, string UserName = "", string Password = "", bool KeepOrignal = false, bool OverwriteExisting = false)
{
this.FtpUserName = UserName;
this.FtpPassword = Password;
this.FtpLocationToWatch = FtpLocationToWatch;
this.DownloadTo = DownloadTo;
this.KeepOrignal = KeepOrignal;
this.RecheckIntervalInSeconds = RecheckIntervalInSeconds;
this.OverwriteExisting = OverwriteExisting;
if (this.RecheckIntervalInSeconds < 1) this.RecheckIntervalInSeconds = 1;
}
public void StartDownloading()
{
JobProcessor = new Timer(this.RecheckIntervalInSeconds * 1000);
JobProcessor.AutoReset = false;
JobProcessor.Enabled = false;
JobProcessor.Elapsed += (sender, e) =>
{
try
{
this.IsRunning = true;
string[] FilesList = GetFilesList(this.FtpLocationToWatch, this.FtpUserName, this.FtpPassword);
if (FilesList == null || FilesList.Length < 1)
{
return;
}
foreach (string FileName in FilesList)
{
if (!string.IsNullOrWhiteSpace(FileName))
{
DownloadFile(this.FtpLocationToWatch, this.DownloadTo, FileName.Trim(), this.FtpUserName, this.FtpPassword, this.OverwriteExisting);
if (!this.KeepOrignal)
{
DeleteFile(Path.Combine(this.FtpLocationToWatch, FileName.Trim()), this.FtpUserName, this.FtpPassword);
}
}
}
this.IsRunning = false;
JobProcessor.Enabled = true;
}
catch (Exception exp)
{
this.IsRunning = false;
JobProcessor.Enabled = true;
Console.WriteLine(exp.Message);
}
};
JobProcessor.Start();
}
public void StopDownloading()
{
try
{
this.JobProcessor.Dispose();
this.IsRunning = false;
}
catch { }
}
private void DeleteFile(string FtpFilePath, string UserName, string Password)
{
FtpWebRequest FtpRequest;
FtpRequest = (FtpWebRequest)FtpWebRequest.Create(new Uri(FtpFilePath));
FtpRequest.UseBinary = true;
FtpRequest.Method = WebRequestMethods.Ftp.DeleteFile;
FtpRequest.Credentials = new NetworkCredential(UserName, Password);
FtpWebResponse response = (FtpWebResponse)FtpRequest.GetResponse();
response.Close();
}
private void DownloadFile(string FtpLocation, string FileSystemLocation, string FileName, string UserName, string Password, bool OverwriteExisting)
{
try
{
const int BufferSize = 2048;
byte[] Buffer = new byte[BufferSize];
FtpWebRequest Request;
FtpWebResponse Response;
if (File.Exists(Path.Combine(FileSystemLocation, FileName)))
{
if (OverwriteExisting)
{
File.Delete(Path.Combine(FileSystemLocation, FileName));
}
else
{
Console.WriteLine(string.Format("File {0} already exist.", FileName));
return;
}
}
Request = (FtpWebRequest)FtpWebRequest.Create(new Uri(Path.Combine(FtpLocation, FileName)));
Request.Credentials = new NetworkCredential(UserName, Password);
Request.Proxy = null;
Request.Method = WebRequestMethods.Ftp.DownloadFile;
Request.UseBinary = true;
Response = (FtpWebResponse)Request.GetResponse();
using (Stream s = Response.GetResponseStream())
{
using (FileStream fs = new FileStream(Path.Combine(FileSystemLocation, FileName), FileMode.CreateNew, FileAccess.ReadWrite))
{
while (s.Read(Buffer, 0, BufferSize) != -1)
{
fs.Write(Buffer, 0, BufferSize);
}
}
}
}
catch { }
}
private string[] GetFilesList(string FtpFolderPath, string UserName, string Password)
{
try
{
FtpWebRequest Request;
FtpWebResponse Response;
Request = (FtpWebRequest)FtpWebRequest.Create(new Uri(FtpFolderPath));
Request.Credentials = new NetworkCredential(UserName, Password);
Request.Proxy = null;
Request.Method = WebRequestMethods.Ftp.ListDirectory;
Request.UseBinary = true;
Response = (FtpWebResponse)Request.GetResponse();
StreamReader reader = new StreamReader(Response.GetResponseStream());
string Data = reader.ReadToEnd();
return Data.Split('\n');
}
catch
{
return null;
}
}
}
The way I handle this is to upload a one 8 element byte array, named ".ftpComplete". The 7 FileSystemWatcher only watches for ".ftpComplete" files, and 6 strips that off the end to know the actual 5 file uploaded. Since the".ftpComplete" file 4 is only 1 byte, it uploads about as fast 3 as it is created on the FTP server, so it 2 can be deleted once you do whatever you 1 need to with the main uploaded file
FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(
FTPAddress + "/" + Path.GetFileName(filePath) + ".ftpComplete");
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential(username, password);
request.UsePassive = true;
request.UseBinary = true;
request.KeepAlive = false;
byte[] buffer = new byte[1];
Stream reqStream = request.GetRequestStream();
reqStream.Write(buffer, 0, buffer.Length);
reqStream.Close();
You could use a Robo-FTP script to monitor 9 the FTP site for changes. Here is a link 8 to a sample script that sends an email whenever 7 a change is detected: http://kb.robo-ftp.com/script_library/show/40
I looked at the previous 6 question that you linked. I think you should 5 be able to modify the Robo-FTP sample and 4 use the SETLEFT command with the /split option 3 to make it parse the folder name and ISO 2 file number of the changed file and then 1 move the file to the proper location.
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.