C# 从 FTP 服务器下载新的和修改过的文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9946862/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Download new and modified files from an FTP server
提问by Noelle
I'm trying to get a list of the files on an FTP server, then one by one check if that file exists on the local system and if it does compare the dates modified and if the ftp file is newer download it.
我正在尝试获取 FTP 服务器上的文件列表,然后一项一项检查本地系统上是否存在该文件,是否确实比较了修改日期以及 ftp 文件是否较新,请下载它。
private void btnGo_Click(object sender, EventArgs e)
{
string[] files = GetFileList();
foreach (string file in files)
{
if (file.Length >= 5)
{
string uri = "ftp://" + ftpServerIP + "/" + remoteDirectory + "/" + file;
Uri serverUri = new Uri(uri);
CheckFile(file);
}
}
this.Close();
}
public string[] GetFileList()
{
string[] downloadFiles;
StringBuilder result = new StringBuilder();
WebResponse response = null;
StreamReader reader = null;
try
{
FtpWebRequest reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + ftpServerIP + "/" + remoteDirectory));
reqFTP.UseBinary = true;
reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
reqFTP.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
reqFTP.Proxy = null;
reqFTP.KeepAlive = false;
reqFTP.UsePassive = false;
response = reqFTP.GetResponse();
reader = new StreamReader(response.GetResponseStream());
string line = reader.ReadLine();
while (line != null)
{
result.Append(line);
result.Append("\n");
line = reader.ReadLine();
}
result.Remove(result.ToString().LastIndexOf('\n'), 1);
return result.ToString().Split('\n');
}
catch
{
if (reader != null)
{
reader.Close();
}
if (response != null)
{
response.Close();
}
downloadFiles = null;
return downloadFiles;
}
}
private void CheckFile(string file)
{
string dFile = file;
string[] splitDownloadFile = Regex.Split(dFile, " ");
string fSize = splitDownloadFile[13];
string fMonth = splitDownloadFile[14];
string fDate = splitDownloadFile[15];
string fTime = splitDownloadFile[16];
string fName = splitDownloadFile[17];
string dateModified = fDate + "/" + fMonth+ "/" + fYear;
DateTime lastModifiedDF = Convert.ToDateTime(dateModified);
string[] filePaths = Directory.GetFiles(localDirectory);
// if there is a file in filePaths that is the same as on the server compare them and then download if file on server is newer
foreach (string ff in filePaths)
{
string[] splitFile = Regex.Split(ff, @"\");
string fileName = splitFile[2];
FileInfo fouFile = new FileInfo(ff);
DateTime lastChangedFF = fouFile.LastAccessTime;
if (lastModifiedDF > lastChangedFF) Download(fileName);
}
}
In the check file method, for each file (they are .exe files) I keep getting different results when I split the string i.e. for one file the file name was at column 18 another it was at 16 etc. I also can't always get the year portion of the file.
在检查文件方法中,对于每个文件(它们是 .exe 文件),当我拆分字符串时,我不断得到不同的结果,即对于一个文件,文件名在第 18 列,另一个在第 16 列,等等。我也不能总是获取文件的年份部分。
采纳答案by lnmx
Option A: I'd recommend that you use a higher-level FTP client library that handles some of these details for you, a few likely options are:
选项 A:我建议您使用更高级别的 FTP 客户端库来为您处理其中一些细节,一些可能的选项是:
Option B: To answer your question more directly, I think the issue is with this line:
选项 B:为了更直接地回答您的问题,我认为问题出在这一行:
string[] splitDownloadFile = Regex.Split(dFile, " ");
It seems like the FTP server is using spaces to right-align the filenames. To deal with that, we want to adjust the regex to consume all whitespace between the fields:
似乎 FTP 服务器正在使用空格来右对齐文件名。为了解决这个问题,我们想调整正则表达式以消耗字段之间的所有空白:
string[] splitDownloadFile = Regex.Split(dFile, "\s+");
...where \s stands for any whitespace character (usually tabs or spaces), and + means one or more of the thing to the left of it. This will not handle edge cases, such as file names with spaces in them.
...其中 \s 代表任何空白字符(通常是制表符或空格),而 + 表示它左侧的一个或多个内容。这不会处理边缘情况,例如其中包含空格的文件名。
回答by Mickey
Here is an exerpt from the FTPclientsource which shows you how they are building their. FtpFileInfo objects. I'm not able to test to this make sure this will work in all cases at the moment, but maybe it will give you some ideas.
这是FTPclient源的摘录,它向您展示了他们如何构建自己的。FtpFileInfo 对象。我无法对此进行测试以确保目前在所有情况下都可以使用,但也许它会给您一些想法。
/// <summary>
/// Return a detailed directory listing, and also download datetime stamps if specified
/// </summary>
/// <param name="directory">Directory to list, e.g. /pub/etc</param>
/// <param name="doDateTimeStamp">Boolean: set to True to download the datetime stamp for files</param>
/// <returns>An FTPDirectory object</returns>
public FTPdirectory ListDirectoryDetail(string directory, bool doDateTimeStamp)
{
System.Net.FtpWebRequest ftp = GetRequest(GetDirectory(directory));
// Set request to do simple list
ftp.Method = System.Net.WebRequestMethods.Ftp.ListDirectoryDetails;
string str = GetStringResponse(ftp);
// replace CRLF to CR, remove last instance
str = str.Replace("\r\n", "\r").TrimEnd('\r');
// split the string into a list
FTPdirectory dir = new FTPdirectory(str, _lastDirectory);
// download timestamps if requested
if (doDateTimeStamp)
{
foreach (FTPfileInfo fi in dir)
{
fi.FileDateTime = this.GetDateTimestamp(fi);
}
}
return dir;
}
/// <summary>
/// Obtain datetimestamp for remote file
/// </summary>
/// <param name="filename"></param>
/// <returns></returns>
public DateTime GetDateTimestamp(string filename)
{
string path;
if (filename.Contains("/"))
{
path = AdjustDir(filename);
}
else
{
path = this.CurrentDirectory + filename;
}
string URI = this.Hostname + path;
FtpWebRequest ftp = GetRequest(URI);
ftp.Method = WebRequestMethods.Ftp.GetDateTimestamp;
return this.GetLastModified(ftp);
}
回答by ?zgür Kara
First of all, there are some components for which you can get info and download data from ftp can be found here: http://www.limilabs.com/ftp
首先,您可以在此处找到一些组件,您可以从 ftp 获取信息和下载数据:http: //www.limilabs.com/ftp
I wrote some methods for get filename and last modified date from ftp.
我写了一些从 ftp 获取文件名和上次修改日期的方法。
This is how I get the filename from line:
这就是我从行获取文件名的方式:
private string GetFtpName(string line)
{
for (int i = 0; i < 8; i++)
line = line.Substring(line.IndexOf(" ")).Trim();
return line;
}
And this is how I get the last modified date from ftp:
这就是我从 ftp 获取最后修改日期的方式:
private DateTime GetFtpFileDate(string url, ICredentials credential)
{
FtpWebRequest rd = (FtpWebRequest)WebRequest.Create(url);
rd.Method = WebRequestMethods.Ftp.GetDateTimestamp;
rd.Credentials = credential;
FtpWebResponse response = (FtpWebResponse)rd.GetResponse();
DateTime lmd = response.LastModified;
response.Close();
return lmd;
}
回答by abatishchev
Try
尝试
ListDirectory + GetDateTimestamp
instead of
代替
ListDirectoryDetails
回答by Martin Prikryl
For this, you need to retrieve a remote directory listing, including timestamps.
为此,您需要检索远程目录列表,包括时间戳。
Unfortunately, there's no really reliable and efficient way to retrieve timestamps using features offered by the .NET framework as it does not support the FTP MLSDcommand. The MLSDcommand provides listing of remote directory in a standardized machine-readable format. The command and the format is standardized by the RFC 3659.
不幸的是,没有真正可靠和有效的方法来使用 .NET 框架提供的功能来检索时间戳,因为它不支持 FTPMLSD命令。该MLSD命令以标准化的机器可读格式提供远程目录列表。命令和格式由RFC 3659标准化。
Alternatives you can use, that are supported by the .NET framework (as the other answers show):
您可以使用的替代方案,由 .NET 框架支持(如其他答案所示):
the
ListDirectoryDetailsmethod(the FTPLISTcommand) to retrieve details of all files in a directory and then you deal with FTP server specific format of the details (*nix format similar tols*nix command is the most common, drawback is that the format may change over time, as for newer files "May 8 17:48" format is used and for older files "Oct 18 2009" format is used)DOS/Windows format: C# class to parse WebRequestMethods.Ftp.ListDirectoryDetails FTP response
*nix format: Parsing FtpWebRequest ListDirectoryDetails linethe
GetDateTimestampmethod(an FTPMDTMcommand) to individually retrieve timestamps for each file. An advantage is that the response is standardized by the RFC 3659toYYYYMMDDHHMMSS[.sss]. A disadvantage is that you have to send a separate request for each file, what can be quite inefficient.const string uri = "ftp://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);
该
ListDirectoryDetails方法(的FTPLIST命令)来检索目录中的所有文件的详细信息,然后你处理的细节FTP服务器的特定格式(*类似于nix的格式ls* nix的命令是最常见的,缺点是格式可能会改变过时间,对于较新的文件使用“May 8 17:48”格式,对于较旧的文件使用“Oct 18 2009”格式)DOS/Windows 格式:C# 类解析 WebRequestMethods.Ftp.ListDirectoryDetails FTP 响应
*nix 格式:解析 FtpWebRequest ListDirectoryDetails 行单独检索每个文件的时间戳的
GetDateTimestamp方法(FTPMDTM命令)。一个优点是响应由RFC 3659标准化为YYYYMMDDHHMMSS[.sss]. 一个缺点是您必须为每个文件发送一个单独的请求,这可能非常低效。const string uri = "ftp://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);
Alternatively you can use a 3rd party FTP client implementation that supports the modern MLSDcommand.
或者,您可以使用支持现代MLSD命令的 3rd 方 FTP 客户端实现。
For example the WinSCP .NET assemblysupports that.
例如,WinSCP .NET 程序集支持这一点。
You can use the Session.ListDirectoryor the Session.EnumerateRemoteFilesmethods and read the RemoteFileInfo.LastWriteTimeof the files in returned collection.
您可以使用Session.ListDirectory或Session.EnumerateRemoteFiles方法并读取RemoteFileInfo.LastWriteTime返回集合中文件的 。
Or even easier, you can use the Session.SynchronizeDirectoriesto have the library automatically download (synchronize) the modified files:
或者更简单,您可以使用 使Session.SynchronizeDirectories库自动下载(同步)修改后的文件:
// Setup session options
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Ftp,
HostName = "ftp.example.com",
UserName = "user",
Password = "mypassword",
};
using (Session session = new Session())
{
// Connect
session.Open(sessionOptions);
// Synchronize files
session.SynchronizeDirectories(
SynchronizationMode.Local, @"d:\www", "/remote/path", false).Check();
}
(I'm the author of WinSCP)
(我是 WinSCP 的作者)

