在ASP.NET / C#中监视FTP目录

问题描述 投票:1回答:3

我有FileSystem观察者的本地目录。它工作正常。我想要同样实现FTP。有什么办法可以实现吗?我检查了很多解决方案,但目前尚不清楚。

逻辑:想要在某个时间戳之后从FTP获取文件。 面临的问题:从FTP获取所有文件然后过滤结果是达到性能(使用FtpWebRequest)。

有没有正确的方法来做到这一点? (WinSCP暂停。现在不能使用它。)

FileSystemWatcher oFsWatcher = new FileSystemWatcher();
OFSWatchers.Add(oFsWatcher);
oFsWatcher.Path = sFilePath;

oFsWatcher.Filter = string.IsNullOrWhiteSpace(sFileFilter) ? "*.*" : sFileFilter;
oFsWatcher.NotifyFilter = NotifyFilters.FileName;

oFsWatcher.EnableRaisingEvents = true;
oFsWatcher.IncludeSubdirectories = bIncludeSubdirectories;
oFsWatcher.Created += new FileSystemEventHandler(OFsWatcher_Created);
c# .net ftp filesystemwatcher ftpwebrequest
3个回答
1
投票

除非您有权访问托管服务的操作系统;这会有点困难。

FileSystemWatcher在文件系统上放置一个钩子,一旦发生事件就会通知你的应用程序。

FTP command specifications没有这样的钩子。除此之外,它始终由客户发起。

因此,要实现这样的逻辑,你应该定期执行NLST列出FTP目录内容并自己跟踪更改(或哈希,或许(MDTM))。

更多信息:


1
投票

您不能使用FileSystemWatcher或任何其他方式,因为FTP协议没有任何API来通知客户端有关远程目录中的更改。

您所能做的就是定期迭代远程树并查找更改。

如果您使用支持远程树的递归列表的FTP客户端库,它实际上很容易实现。不幸的是,内置的.NET FTP客户端,FtpWebRequest没有。但是例如使用WinSCP .NET assembly,你可以使用Session.EnumerateRemoteFiles method

请参阅文章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);
    }
}

(我是WinSCP的作者)


但是,如果您确实只想下载更改,那么这样做会更容易。只需在循环中使用Session.SynchronizeDirectories即可。

while (true)
{
    SynchronizationResult result =
        session.SynchronizeDirectories(
            SynchronizationMode.Local, "/remote/path", @"C:\local\path", true);
    result.Check();
    // You can inspect result.Downloads for a list for updated files

    Console.WriteLine("Sleeping 10s...");
    Thread.Sleep(10000);
}

这将更新甚至修改过的文件,而不仅仅是新文件。


虽然从Web应用程序使用WinSCP .NET程序集可能会有问题。如果您不想使用第三方库,则必须考虑FtpWebRequest的限制。有关如何使用FtpWebRequest递归列出远程目录树的示例,请参阅我对List names of files in FTP directory and its subdirectories的回答。


您已编辑过您的问题,表示您对我建议的解决方案存在性能问题。虽然您已经提出了一个涵盖此问题的新问题: Get FTP file details based on datetime in C#


0
投票

我有一个替代解决方案来完成我的功能。

说明:

我正在从具有相同文件夹结构的FTP(读取权限请求)下载文件。

因此,每次作业/服务运行时,我都可以检查物理路径是否存在相同文件(完整路径)如果不存在则可以将其视为新文件。而Ii也可以做同样的动作并下载。

它只是一个替代解决方案。

代码更改:

 private static void GetFiles()
 {
    using (FtpClient conn = new FtpClient())
    {
        string ftpPath = "ftp://myftp/";

        string downloadFileName = @"C:\temp\FTPTest\";

        downloadFileName +=  "\\";

        conn.Host = ftpPath;
        //conn.Credentials = new NetworkCredential("ftptest", "ftptest");
        conn.Connect();

        //Get all directories

        foreach (FtpListItem item in conn.GetListing(conn.GetWorkingDirectory(),
            FtpListOption.Modify | FtpListOption.Recursive))
        {
            // if this is a file
            if (item.Type == FtpFileSystemObjectType.File)
            {
                string localFilePath = downloadFileName + item.FullName;

                //Only newly created files will be downloaded.
                if (!File.Exists(localFilePath))
                {
                    conn.DownloadFile(localFilePath, item.FullName);
                    //Do any action here.
                    Console.WriteLine(item.FullName);
                }
            }
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.