如何获取FTP服务器上文件的上次修改日期

本文关键字:文件 日期 修改 服务器 FTP 何获取 获取 | 更新日期: 2023-09-27 18:35:09

这是我的代码

FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.Create(FTPAddress);
ftpRequest.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
FtpWebResponse response = (FtpWebResponse)ftpRequest.GetResponse();
StreamReader streamReader = new StreamReader(response.GetResponseStream());
List<string> directories = new List<string>();
string line = streamReader.ReadLine();
while (!string.IsNullOrEmpty(line))
{
    directories.Add(line);
    line = streamReader.ReadLine();
}

如您所见,我正在使用ListDirectoryDetails.

对于directories中的每一行,这是内容:

ftp://172.28.4.7//12-22-14  01:21PM                 9075 fileName.xml

我的问题是如何从那条线上获取时间?我应该解析字符串吗?我不这么认为,因为我读到有LastModified属性,但我不知道如何使用它。

你能帮我吗?

如何获取FTP服务器上文件的上次修改日期

不幸的是,没有真正可靠和有效的方法来使用 .NET 框架提供的功能检索目录中所有文件的修改时间戳,因为它不支持 FTP MLSD 命令。MLSD 命令以标准化的机器可读格式提供远程目录列表。命令和格式由 RFC 3659 标准化。

可以使用的 .NET 框架支持的替代方法:

  • ListDirectoryDetails方法(FTP LIST命令)检索目录中所有文件的详细信息,然后处理FTP服务器特定格式的详细信息

    DOS/Windows 格式:用于解析 WebRequestMethods.Ftp.ListDirectoryDetails FTP response
    的 C# 类*nix 格式:解析 FtpWebRequest ListDirectoryDetails 行

  • GetDateTimestamp方法(FTP MDTM命令)单独检索每个文件的时间戳。优点是响应由 RFC 3659 标准化为 YYYYMMDDHHMMSS[.sss] 。缺点是您必须为每个文件发送单独的请求,这可能效率很低。此方法使用您提到的 LastModified 属性:

      const string uri = "ftp://example.com/remote/path/file.txt";
      FtpWebRequest request = (FtpWebRequest)WebRequest.Create(uri);
      request.Method = WebRequestMethods.Ftp.GetDateTimestamp;
      FtpWebResponse response = (FtpWebResponse)request.GetResponse();
      Console.WriteLine("{0} {1}", uri, response.LastModified);
    
<小时 />

或者,您可以使用支持新式 MLSD 命令的第三方 FTP 客户端实现。

例如,WinSCP .NET 程序集支持这一点。

// Setup session options
SessionOptions sessionOptions = new SessionOptions
{
    Protocol = Protocol.Ftp,
    HostName = "example.com",
    UserName = "username",
    Password = "password",
};
using (Session session = new Session())
{
    // Connect
    session.Open(sessionOptions);
    // Get list of files in the directory
    string remotePath = "/remote/path/";
    RemoteDirectoryInfo directoryInfo = session.ListDirectory(remotePath);
    foreach (RemoteFileInfo fileInfo in directoryInfo.Files)
    {
        Console.WriteLine("{0} {1}", fileInfo.Name, fileInfo.LastWriteTime);
    }    
}

(我是WinSCP的作者)

尝试使用 MS 文档中的以下代码:

  // Get the object used to communicate with the server.
  Uri serverUri = new Uri("ftp://mypath/myfile.txt");
  FtpWebRequest request = (FtpWebRequest)WebRequest.Create (serverUri);
  request.Method = WebRequestMethods.Ftp.GetDateTimestamp;
  FtpWebResponse response = (FtpWebResponse)request.GetResponse ();
  DateTime lastModifiedDate = response.LastModified;

http://msdn.microsoft.com/en-us/library/system.net.ftpwebresponse.lastmodified%28v=vs.110%29.aspx

您应该为每个文件执行此操作。要做到这一点,也不简单。您必须从目录列表响应中解析结果。

检查这家伙是如何做到这一点的:从WebRequestMethods.Ftp.ListDirectory详细信息中提取文件名您应该能够在每行读取时执行 foreach 操作。

这已经有几年的历史了,但想分享我的解决方案,因为我不得不这样做。

我使用了获取FTP目录列表的MSDN示例:https://learn.microsoft.com/en-us/dotnet/framework/network-programming/how-to-list-directory-contents-with-ftp

这个正则表达式解析结果的答案(我实际上使用了 Nyerguds 的评论): https://stackoverflow.com/a/1329074/2246411

这是我编写的用于"重新膨胀"目录列表中的对象的简单类(目前它只执行顶级文件夹,但希望我可以改进它并在此处更新它:https://gist.github.com/derekantrican/9e890c06ed17ddc561d8af02e41c34c8):

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
namespace FTPHelper
{
    public class FTPItem
    {
        public char[] Permissions { get; set; }
        public int Size { get; set; }
        public DateTime LastModified { get; set; }
        public string Name { get; set; }
        public string FullPath { get; set; }
        public override string ToString()
        {
            return Name;
        }
    }
    public class FTPDirectory : FTPItem
    {
        public FTPDirectory() { }
        public FTPDirectory(FTPItem item)
        {
            Permissions = item.Permissions;
            Size = item.Size;
            LastModified = item.LastModified;
            Name = item.Name;
            FullPath = item.FullPath;
        }
        public Lazy<List<FTPItem>> SubItems { get; set; }
    }
    public class FTPFile : FTPItem
    {
        public FTPFile() { }
        public FTPFile(FTPItem item)
        {
            Permissions = item.Permissions;
            Size = item.Size;
            LastModified = item.LastModified;
            Name = item.Name;
            FullPath = item.FullPath;
        }
    }
    public class FTPClient
    {
        private string address;
        private string username;
        private string password;
        public FTPClient(string address, string username, string password)
        {
            this.address = address.StartsWith("ftp://", StringComparison.OrdinalIgnoreCase) ? address : $"ftp://{address}";
            this.username = username;
            this.password = password;
        }
        public List<FTPItem> RetrieveDirectoryListingsFromFTP(string startingPath = null)
        {
            List<FTPItem> results = new List<FTPItem>();
            string path = !string.IsNullOrEmpty(startingPath) ? startingPath.Replace(" ", "%20") : address;
            path = !path.StartsWith(address) ? $"{address}/{path}" : path;
            FtpWebRequest request = (FtpWebRequest)WebRequest.Create(path);
            request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
            request.Credentials = new NetworkCredential(username, password);
            request.KeepAlive = false;
            request.UseBinary = true;
            request.UsePassive = true;
            Regex directoryListingRegex = new Regex(@"^([d-])((?:[rwxt-]{3}){3})'s+'d{1,}'s+.*?('d{1,})'s+('w+)'s+('d{1,2})'s+('d{4})?('d{1,2}:'d{2})?'s+(.+?)'s?$",
                                    RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
            using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
            {
                using (Stream responseStream = response.GetResponseStream())
                {
                    using (StreamReader reader = new StreamReader(responseStream))
                    {
                        string line;
                        while ((line = reader.ReadLine()) != null)
                        {
                            Match match = directoryListingRegex.Match(line);
                            FTPItem item = new FTPItem
                            {
                                Permissions = match.Groups[2].Value.ToArray(),
                                Size = int.Parse(match.Groups[3].Value),
                                LastModified = DateTime.ParseExact($"{match.Groups[4]} {match.Groups[5]} {match.Groups[6]} {match.Groups[7]}",
                                                    $"MMM dd {(match.Groups[6].Value != "" ? "yyyy" : "")} {(match.Groups[7].Value != "" ? "HH:mm" : "")}",
                                                    CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal),
                                Name = match.Groups[8].Value,
                                FullPath = $"{path}/{match.Groups[8].Value.Replace(" ", "%20")}",
                            };
                            if (match.Groups[1].Value == "d")
                            {
                                FTPDirectory dir = new FTPDirectory(item);
                                dir.SubItems = new Lazy<List<FTPItem>>(() => RetrieveDirectoryListingsFromFTP(dir.FullPath));
                                results.Add(dir);
                            }
                            else
                            {
                                FTPFile file = new FTPFile(item);
                                results.Add(file);
                            }
                        }
                    }
                }
            }
            return results;
        }
    }
}