使用 FluentFTP 从 FTP 同时下载多个文件
Download multiple files simultaneously from FTP using FluentFTP
我正在使用 FluentFTP 从 FTP
进行连接、下载等
https://github.com/robinrodricks/FluentFTP/wiki
我想从列表中同时下载文件。一个一个下载都没有问题
我的代码是这样的:
下载功能:
public async Task<bool> DownloadFileAsync(string RemoteUrl, string AppName, Progress<FtpProgress> progress = null)
{
return await Task.Run(async() =>
{
using (FileStream read = new FileStream("settings.xml", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
if (ftpClient.IsConnected)
{
if (File.Exists("settings.xml"))
{
Information info = (Information)xs.Deserialize(read);
if (Directory.Exists(info.Downloads))
{
bool DownloadFinished = await ftpClient.DownloadFileAsync(info.Downloads + "\" + AppName, RemoteUrl, FtpLocalExists.Overwrite, FtpVerify.Retry, progress);
if (DownloadFinished == true)
{
loger.LogWrite("File " + RemoteUrl + " downloaded succesfully.");
//read.Dispose();
return true;
}
else
{
loger.LogWrite("File" + RemoteUrl + " download failed.");
//read.Dispose();
return false;
}
}
else
{
loger.LogWrite("Could not locate folder " + info.Downloads + " downloading terminated.");
return false;
}
}
else
{
MessageBox.Show("settings.xml file is missing.");
loger.LogWrite("settings.xml file is missing.");
read.Dispose();
return false;
}
}
else
{
loger.LogWrite("FTP Client is not connected could not download: " + RemoteUrl);
read.Dispose();
return false;
}
}
});
}
我如何填写列表:
Arta_Variables.ArtaSoftware.Add(new Software() { RemoteUrl = "Ultra_Script/Basic_SW/Adobe_Reader.exe", SoftwareName = "Adobe_Reader.exe", FileExistsOnRemoteUrl = null, Downloaded = null });
这是一个一个下载它们的方法:
if(Arta_Variables.DAAOChecked == false)
{
if (CheckFinished == true)
{
using (FileStream read = new FileStream("settings.xml", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
XmlSerializer xs = new XmlSerializer(typeof(Information));
Information info = (Information)xs.Deserialize(read);
AddBlackLine("");
AddBlackLine("Downloading all available files.");
AddBlackLine("");
foreach (Software software1 in ArtaChosenSW)
{
string item = software1.SoftwareName;
int index = ArtaChosenSW.FindIndex(p => p.SoftwareName == item);
if (software1.FileExistsOnRemoteUrl == true)
{
AddBlackLine("Downloading " + software1.SoftwareName);
Dispatcher.Invoke(() =>
{
DWGProgressLab.Visibility = Visibility.Visible;
DP_ProgressPercentage.Visibility = Visibility.Visible;
});
Progress<FtpProgress> prog = new Progress<FtpProgress>(x =>
{
int ConvertedInt = (int)x.Progress;
DP_ProgressPercentage.Dispatcher.BeginInvoke((Action)(() => DP_ProgressPercentage.Content = ConvertedInt + "%"));
});
bool DWFinished = await ftp.DownloadFileAsync(software1.RemoteUrl, software1.SoftwareName, prog);
if (DWFinished == true)
{
AddGreenLine("Download of " + software1.SoftwareName + " succesfull.");
ArtaChosenSW[index].Downloaded = true;
ArtaChosenSW[index].LocalUrl = info.Downloads;
Dispatcher.Invoke(() =>
{
DWGProgressLab.Visibility = Visibility.Hidden;
DP_ProgressPercentage.Visibility = Visibility.Hidden;
});
}
else
{
AddRedLine("Download of " + software1.SoftwareName + " failed");
ArtaChosenSW[index].FileExistsOnRemoteUrl = false;
}
}
else
{
ArtaChosenSW[index].FileExistsOnRemoteUrl = true;
AddBlackLine("File " + software1.SoftwareName + " did not found on ftp. Could not download.");
loger.LogWrite("File " + software1.SoftwareName + " did not found on ftp. Could not download.");
}
}
}
}
}
我同时下载的尝试:
foreach(Software software in ArtaChosenSW)
{
var tasks = ArtaChosenSW.Select(c => Task.Factory.StartNew(() => ftp.DownloadFileAsync(c.RemoteUrl, c.SoftwareName))).ToArray();
Task.WaitAll(tasks);
}
遗憾的是,它的作用是在本地 url 中创建 0kb 的空白文件,但没有进行下载。
我在异步编程方面经验不多,所以我很高兴得到所有答案或一些更好的方法。
您的所有传输似乎都在使用一个 FtpClient
实例。
FtpClient
代表到 FTP 服务器的一个连接。 FTP 协议不允许通过一个连接进行多个并行传输。您必须为每个并行传输打开一个新连接。
有关实施示例,请参阅 。
根据@Martin Prikryl 的回答,我为并发下载创建了新功能:
完美运行:
public async Task DownloadMultipleFilesConcurrentFromFTP(int NumberOfConnections, string AppName, string RemoteUrl)
{
await Task.Run(async() =>
{
NetworkCredential networkCredential = new NetworkCredential(FTPUsername, FTPPassword);
List<FtpClient> ftpClients = new List<FtpClient>();
for (int i = 0; i < NumberOfConnections; i++)
{
ftpClients.Add(new FtpClient(FTPHost, networkCredential));
foreach(FtpClient ftp in ftpClients)
{
ftp.ConnectTimeout = ConnectTimeout;
ftp.SocketPollInterval = SocketPollInterval;
ftp.ReadTimeout = ReadTimeout;
ftp.DataConnectionConnectTimeout = DataConnectionConnectTimeout;
ftp.DataConnectionReadTimeout = DataConnectionReadTimeout;
ftp.Connect();
if (ftp.IsConnected)
{
using (FileStream read = new FileStream("settings.xml", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
if(ftp.IsConnected == true)
{
if (File.Exists("settings.xml"))
{
Information info = (Information)xs.Deserialize(read);
if (Directory.Exists(info.Downloads))
{
await ftp.DownloadFileAsync(info.Downloads + "\" + AppName, RemoteUrl, FtpLocalExists.Overwrite, FtpVerify.Retry);
}
}
}
}
}
}
}
});
}
现在我只需要弄清楚return所有文件的下载进度。
从您发布的答案中获取您的代码,这应该可以处理多个下载而无需任何线程池或 Task
包装器开销。
public async Task DownloadMultipleFilesConcurrentFromFTP(int NumberOfConnections, string AppName, string RemoteUrl)
{
var downloadTasks = new List<Task>();
for (int i = 0; i < NumberOfConnections; i++){
downloadTasks.Add(DownloadFile(AppName, RemoteUrl));
}
await Task.WhenAll(downloadTasks);
}
public async Task DownloadFile(string AppName, string RemoteUrl)
{
var ftp = new FtpClient(FTPHost, networkCredential);
ftp.ConnectTimeout = ConnectTimeout;
ftp.SocketPollInterval = SocketPollInterval;
ftp.ReadTimeout = ReadTimeout;
ftp.DataConnectionConnectTimeout = DataConnectionConnectTimeout;
ftp.DataConnectionReadTimeout = DataConnectionReadTimeout;
await ftp.ConnectAsync();
if (ftp.IsConnected)
{
using (FileStream read = new FileStream("settings.xml", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
if (ftp.IsConnected == true)
{
if (File.Exists("settings.xml"))
{
Information info = (Information)xs.Deserialize(read);
if (Directory.Exists(info.Downloads))
{
await ftp.DownloadFileAsync(info.Downloads + "\" + AppName, RemoteUrl, FtpLocalExists.Overwrite, FtpVerify.Retry);
}
}
}
}
}
}
它为每次下载创建一个 Task
,然后在任务列表上调用 Task.WhenAll
以等待所有文件完成后再返回。
我没有修改你的任何文件处理代码,但你应该考虑在那里使用你的调用的 async
版本,因为使用阻塞调用访问文件系统会导致响应问题。
我正在使用 FluentFTP 从 FTP
进行连接、下载等
https://github.com/robinrodricks/FluentFTP/wiki
我想从列表中同时下载文件。一个一个下载都没有问题
我的代码是这样的:
下载功能:
public async Task<bool> DownloadFileAsync(string RemoteUrl, string AppName, Progress<FtpProgress> progress = null)
{
return await Task.Run(async() =>
{
using (FileStream read = new FileStream("settings.xml", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
if (ftpClient.IsConnected)
{
if (File.Exists("settings.xml"))
{
Information info = (Information)xs.Deserialize(read);
if (Directory.Exists(info.Downloads))
{
bool DownloadFinished = await ftpClient.DownloadFileAsync(info.Downloads + "\" + AppName, RemoteUrl, FtpLocalExists.Overwrite, FtpVerify.Retry, progress);
if (DownloadFinished == true)
{
loger.LogWrite("File " + RemoteUrl + " downloaded succesfully.");
//read.Dispose();
return true;
}
else
{
loger.LogWrite("File" + RemoteUrl + " download failed.");
//read.Dispose();
return false;
}
}
else
{
loger.LogWrite("Could not locate folder " + info.Downloads + " downloading terminated.");
return false;
}
}
else
{
MessageBox.Show("settings.xml file is missing.");
loger.LogWrite("settings.xml file is missing.");
read.Dispose();
return false;
}
}
else
{
loger.LogWrite("FTP Client is not connected could not download: " + RemoteUrl);
read.Dispose();
return false;
}
}
});
}
我如何填写列表:
Arta_Variables.ArtaSoftware.Add(new Software() { RemoteUrl = "Ultra_Script/Basic_SW/Adobe_Reader.exe", SoftwareName = "Adobe_Reader.exe", FileExistsOnRemoteUrl = null, Downloaded = null });
这是一个一个下载它们的方法:
if(Arta_Variables.DAAOChecked == false)
{
if (CheckFinished == true)
{
using (FileStream read = new FileStream("settings.xml", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
XmlSerializer xs = new XmlSerializer(typeof(Information));
Information info = (Information)xs.Deserialize(read);
AddBlackLine("");
AddBlackLine("Downloading all available files.");
AddBlackLine("");
foreach (Software software1 in ArtaChosenSW)
{
string item = software1.SoftwareName;
int index = ArtaChosenSW.FindIndex(p => p.SoftwareName == item);
if (software1.FileExistsOnRemoteUrl == true)
{
AddBlackLine("Downloading " + software1.SoftwareName);
Dispatcher.Invoke(() =>
{
DWGProgressLab.Visibility = Visibility.Visible;
DP_ProgressPercentage.Visibility = Visibility.Visible;
});
Progress<FtpProgress> prog = new Progress<FtpProgress>(x =>
{
int ConvertedInt = (int)x.Progress;
DP_ProgressPercentage.Dispatcher.BeginInvoke((Action)(() => DP_ProgressPercentage.Content = ConvertedInt + "%"));
});
bool DWFinished = await ftp.DownloadFileAsync(software1.RemoteUrl, software1.SoftwareName, prog);
if (DWFinished == true)
{
AddGreenLine("Download of " + software1.SoftwareName + " succesfull.");
ArtaChosenSW[index].Downloaded = true;
ArtaChosenSW[index].LocalUrl = info.Downloads;
Dispatcher.Invoke(() =>
{
DWGProgressLab.Visibility = Visibility.Hidden;
DP_ProgressPercentage.Visibility = Visibility.Hidden;
});
}
else
{
AddRedLine("Download of " + software1.SoftwareName + " failed");
ArtaChosenSW[index].FileExistsOnRemoteUrl = false;
}
}
else
{
ArtaChosenSW[index].FileExistsOnRemoteUrl = true;
AddBlackLine("File " + software1.SoftwareName + " did not found on ftp. Could not download.");
loger.LogWrite("File " + software1.SoftwareName + " did not found on ftp. Could not download.");
}
}
}
}
}
我同时下载的尝试:
foreach(Software software in ArtaChosenSW)
{
var tasks = ArtaChosenSW.Select(c => Task.Factory.StartNew(() => ftp.DownloadFileAsync(c.RemoteUrl, c.SoftwareName))).ToArray();
Task.WaitAll(tasks);
}
遗憾的是,它的作用是在本地 url 中创建 0kb 的空白文件,但没有进行下载。
我在异步编程方面经验不多,所以我很高兴得到所有答案或一些更好的方法。
您的所有传输似乎都在使用一个 FtpClient
实例。
FtpClient
代表到 FTP 服务器的一个连接。 FTP 协议不允许通过一个连接进行多个并行传输。您必须为每个并行传输打开一个新连接。
有关实施示例,请参阅
根据@Martin Prikryl 的回答,我为并发下载创建了新功能:
完美运行:
public async Task DownloadMultipleFilesConcurrentFromFTP(int NumberOfConnections, string AppName, string RemoteUrl)
{
await Task.Run(async() =>
{
NetworkCredential networkCredential = new NetworkCredential(FTPUsername, FTPPassword);
List<FtpClient> ftpClients = new List<FtpClient>();
for (int i = 0; i < NumberOfConnections; i++)
{
ftpClients.Add(new FtpClient(FTPHost, networkCredential));
foreach(FtpClient ftp in ftpClients)
{
ftp.ConnectTimeout = ConnectTimeout;
ftp.SocketPollInterval = SocketPollInterval;
ftp.ReadTimeout = ReadTimeout;
ftp.DataConnectionConnectTimeout = DataConnectionConnectTimeout;
ftp.DataConnectionReadTimeout = DataConnectionReadTimeout;
ftp.Connect();
if (ftp.IsConnected)
{
using (FileStream read = new FileStream("settings.xml", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
if(ftp.IsConnected == true)
{
if (File.Exists("settings.xml"))
{
Information info = (Information)xs.Deserialize(read);
if (Directory.Exists(info.Downloads))
{
await ftp.DownloadFileAsync(info.Downloads + "\" + AppName, RemoteUrl, FtpLocalExists.Overwrite, FtpVerify.Retry);
}
}
}
}
}
}
}
});
}
现在我只需要弄清楚return所有文件的下载进度。
从您发布的答案中获取您的代码,这应该可以处理多个下载而无需任何线程池或 Task
包装器开销。
public async Task DownloadMultipleFilesConcurrentFromFTP(int NumberOfConnections, string AppName, string RemoteUrl)
{
var downloadTasks = new List<Task>();
for (int i = 0; i < NumberOfConnections; i++){
downloadTasks.Add(DownloadFile(AppName, RemoteUrl));
}
await Task.WhenAll(downloadTasks);
}
public async Task DownloadFile(string AppName, string RemoteUrl)
{
var ftp = new FtpClient(FTPHost, networkCredential);
ftp.ConnectTimeout = ConnectTimeout;
ftp.SocketPollInterval = SocketPollInterval;
ftp.ReadTimeout = ReadTimeout;
ftp.DataConnectionConnectTimeout = DataConnectionConnectTimeout;
ftp.DataConnectionReadTimeout = DataConnectionReadTimeout;
await ftp.ConnectAsync();
if (ftp.IsConnected)
{
using (FileStream read = new FileStream("settings.xml", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
if (ftp.IsConnected == true)
{
if (File.Exists("settings.xml"))
{
Information info = (Information)xs.Deserialize(read);
if (Directory.Exists(info.Downloads))
{
await ftp.DownloadFileAsync(info.Downloads + "\" + AppName, RemoteUrl, FtpLocalExists.Overwrite, FtpVerify.Retry);
}
}
}
}
}
}
它为每次下载创建一个 Task
,然后在任务列表上调用 Task.WhenAll
以等待所有文件完成后再返回。
我没有修改你的任何文件处理代码,但你应该考虑在那里使用你的调用的 async
版本,因为使用阻塞调用访问文件系统会导致响应问题。