FTP の場所を実装するにはどうすればよいですかFileSystemWatcher
(C# で)。アイデアは、何かが FTP の場所に追加されるたびに、ローカル マシンにコピーしたいということです。どんなアイデアも役に立ちます。
これは、私の以前の質問Selective FTP download using .NETのフォローアップです。
FTP の場所を実装するにはどうすればよいですかFileSystemWatcher
(C# で)。アイデアは、何かが FTP の場所に追加されるたびに、ローカル マシンにコピーしたいということです。どんなアイデアも役に立ちます。
これは、私の以前の質問Selective FTP download using .NETのフォローアップです。
ディレクトリの内容を定期的に要求し続けるポーリング ソリューションを実装する必要があります。これを前回の呼び出しでキャッシュされたリストと比較し、何が起こったのかを判断します。
残念ながら、FTP プロトコルには、これに役立つものは何もありません。
FileSystemWatcher
FTP プロトコルには、リモート ディレクトリの変更をクライアントに通知する API がないため、 またはその他の方法を使用することはできません。
できることは、リモート ツリーを定期的に反復して変更を見つけることだけです。
リモート ツリーの再帰的なリストをサポートする FTP クライアント ライブラリを使用すれば、実際にはかなり簡単に実装できます。残念ながら、組み込みの .NET FTP クライアントにはありFtpWebRequest
ません。しかし、たとえばWinSCP .NET アセンブリでは、Session.EnumerateRemoteFiles
メソッドを使用できます。
記事SFTP/FTP サーバーの変更の監視 を参照してください。
// 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);
}
}
(私は WinSCP の作者です)
ただし、実際に変更をダウンロードするだけの場合は、はるかに簡単です。Session.SynchronizeDirectories
ループ内で使用するだけです。
session.SynchronizeDirectories(
SynchronizationMode.Local, "/remote/path", @"C:\local\path", true).Check();
ローカル ディレクトリを最新に保つ (変更されたファイルをリモート SFTP/FTP サーバーからダウンロードする)の記事を参照して ください。
サードパーティのライブラリを使用したくない場合は、FtpWebRequest
. を使用してリモート ディレクトリ ツリーを再帰的に一覧表示する方法の例については、C# Download all files and subdirectories through FTPFtpWebRequest
に対する私の回答を参照してください。
このFileSystemWatcher
クラスは、ホスト Windows オペレーティング システムにイベントを登録することによって機能します。そのため、Windows システムでホストされているディレクトリへのローカル パスと UNC パスでの作業に制限されています。の MSDN ドキュメントでFileSystemWatcher
は、使用できるパスと、クラスを使用する際の潜在的な問題について説明しています。
FTP サイトの変更について警告を受けたい場合は、ポーリング メカニズムを使用して、監視対象のファイルまたはフォルダーの現在の状態を確認する必要があります。変更の FTP サイトのスナップショットを比較し、変更を検出したときに同様のイベントを発生させることで、ファイルがいつ追加および削除されたかを確認できます。残念ながら、名前変更イベントを検出することはできませんが、他の変更はこの方法で簡単に監視できるはずです。
次の方法でFTPの場所を監視できます。
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;
}
}
}
FTP の場所を指す、FileSystemWatcher を作成する簡単なサービスを作成します。
次に、ファイルがアップロードまたは変更されると、サービスでイベントが発生します。これを使用して、ファイルをローカル マシンにコピーできます。
File.Copy など
見てください:このブログ
Robo-FTPスクリプトを使用して、FTPサイトの変更を監視できます。変更が検出されるたびに電子メールを送信するサンプルスクリプトへのリンクは次のとおりです。http: //kb.robo-ftp.com/script_library/show/40
あなたがリンクした前の質問を見ました。Robo-FTPサンプルを変更し、 SETLEFTコマンドを/ splitオプションとともに使用して、変更されたファイルのフォルダー名とISOファイル番号を解析し、ファイルを適切な場所に移動できるようにする必要があると思います。