C# 使用FluentFTP从FTP同时下载多个文件

C# 使用FluentFTP从FTP同时下载多个文件,c#,.net,asynchronous,ftp,fluentftp,C#,.net,Asynchronous,Ftp,Fluentftp,我正在使用FluentFTP从FTP连接、下载等 我想从列表中同时下载文件。一个接一个地下载它们没有问题 我的代码是这样的: 下载功能: public async Task<bool> DownloadFileAsync(string RemoteUrl, string AppName, Progress<FtpProgress> progress = null) { return await Task.Run(async() =>

我正在使用FluentFTP从FTP连接、下载等

我想从列表中同时下载文件。一个接一个地下载它们没有问题

我的代码是这样的:

下载功能:

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;
                }
            }
        });

    }
以下是一个接一个下载它们的方式:

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.");
                }
            }
        }
    }
}
可悲的是,它在本地url中创建了0 KB的空白文件,但没有下载


我在异步编程方面没有太多经验,所以我很高兴能找到所有答案或一些更好的方法。

看来您在所有传输中都使用了一个
FtpClient
实例

FtpClient
表示到FTP服务器的一个连接。FTP协议不允许在一个连接上进行多个并行传输。您必须为每次并行传输打开一个新连接


有关实现的示例,请参见。

基于@Martin Prikryl answer,我创建了用于并发下载的新函数:

完美地工作:

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);
                                }
                            }
                        }
                    }
                }
            }
        }
    });
}
公共异步任务从FTP下载MultipleFileConcurrentFromFTP(int NumberOfConnections、string AppName、string RemoteUrl)
{
等待任务。运行(异步()=>
{
NetworkCredential NetworkCredential=新的网络凭据(FTPUsername、FTPPassword);
List ftpClients=新列表();
对于(int i=0;i

现在我只需要弄清楚如何返回所有文件的下载进度。

从您发布的答案中获取代码,这应该可以处理多次下载,而不需要任何线程池或
任务
包装器开销

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);
                    }
                }
            }
        }
    }
}
公共异步任务从FTP下载MultipleFileConcurrentFromFTP(int NumberOfConnections、string AppName、string RemoteUrl)
{
var downloadTasks=新列表();
对于(int i=0;i
它为每次下载创建一个
任务
,然后调用任务列表中的
Task.whalll
,等待所有文件完成后返回


我没有修改任何文件处理代码,但是你也应该考虑使用<代码> Aycyc>代码>版本,因为使用阻塞调用访问文件系统会引起响应性问题。

如果你不使用<代码>任务,这将更好地工作。而是为每个下载作业创建了一个普通的
任务
,并用
任务等待它们。这将允许您直接从下载
任务中报告进度,并有助于避免多线程问题。您还应该等待
ftp.ConnectAsync()
,而不是调用
ftp.Connect()
@BradleyUffner。我认为此行是为每个ftpclient:var tasks=ArtaChosenSW创建任务。选择(c=>Task.Factory.StartNew(()=>ftp.DownloadMultipleFilesConcurrentFromFTP(ArtaChosenSW.Count,c.RemoteUrl,c.SoftwareName))).ToArray();有点像。它围绕着匿名
委托的调用创建了一个
任务
,该任务在线程退出时完成。基本上,它是在线程池中的另一个线程上运行的代码的包装器,这在与UI交互时增加了一些低效性和复杂性。如果要这样做这不需要使用
任务。运行
,完全不需要涉及多线程就可以完成。重温这个答案,我认为它不再是一个好的选择
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);
                                }
                            }
                        }
                    }
                }
            }
        }
    });
}
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);
                    }
                }
            }
        }
    }
}