在 .NET Core 中使用一个连接下载多个文件 FTP
Download multiple files over FTP using one connection in .NET Core
我正在尝试通过一个打开的连接将多个文件下载到内存中。
我从该文档中得知:https://docs.microsoft.com/en-us/dotnet/api/system.net.ftpwebrequest.keepalive – FtpWebRequest
默认 KeepAlive
为真。
if the connection to the server should not be destroyed; otherwise, false. The default value is true.
我创建了这段代码:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
namespace ConsoleApp23
{
class Program
{
static void Main(string[] args)
{
String[] files = FTPListTree("ftp://server.com", "user", "password");
for (int i = 0; i <= files.Count() - 1; i++)
{
string path = files[i].ToString();
var request = (FtpWebRequest)WebRequest.Create(path);
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.Credentials = new NetworkCredential("user", "password");
request.Timeout = 100000;
request.KeepAlive = true;
request.ConnectionGroupName = "DownloadFilesGroup";
request.ServicePoint.ConnectionLimit = 8;
using (var response = (FtpWebResponse)request.GetResponse())
{
using (var stream = response.GetResponseStream())
{
var ms = new MemoryStream();
stream.CopyTo(ms);
var a = ms.ToArray();
string ss = Encoding.UTF8.GetString(a);
Console.WriteLine(ss);
}
}
}
}
public static String[] FTPListTree(String ftpUri, String user, String pass)
{
try
{
List<String> files = new List<String>();
Queue<String> folders = new Queue<String>();
folders.Enqueue(ftpUri);
while (folders.Count > 0)
{
String fld = folders.Dequeue();
List<String> newFiles = new List<String>();
FtpWebRequest ftp = (FtpWebRequest)FtpWebRequest.Create(fld);
ftp.Timeout = 20000;
ftp.Credentials = new NetworkCredential(user, pass);
ftp.Method = WebRequestMethods.Ftp.ListDirectory;
using (StreamReader resp = new StreamReader(ftp.GetResponse().GetResponseStream()))
{
String line = resp.ReadLine();
while (line != null)
{
newFiles.Add(line.Trim());
line = resp.ReadLine();
}
}
ftp = (FtpWebRequest)FtpWebRequest.Create(fld);
ftp.Timeout = 20000;
ftp.Credentials = new NetworkCredential(user, pass);
ftp.Method = WebRequestMethods.Ftp.ListDirectory;
using (StreamReader resp = new StreamReader(ftp.GetResponse().GetResponseStream()))
{
String line = resp.ReadLine();
while (line != null)
{
if (!Path.HasExtension(line))
{
String dir = newFiles.First(x => line.EndsWith(x));
newFiles.Remove(dir);
folders.Enqueue(fld + dir + "/");
}
line = resp.ReadLine();
}
}
files.AddRange(from f in newFiles select fld + f);
}
return files.ToArray();
}
catch (Exception e)
{
throw;
}
}
}
}
这是处理的正确方法吗?我似乎找不到任何关于如果处理 response
或响应流,将关闭控制连接,keepalive 将保持打开状态的文档。
有什么方法可以在 运行 时记录下来,以便我可以看到 FTP 调用?我自己无法访问 FTP 服务器。
更新
我实际上已经用测试 FTP 和上面的代码对此进行了测试,即使它有 KeepAlive=true
,它也会在每个请求上使用新连接。我用 Fluent API: https://github.com/robinrodricks/FluentFTP/blob/master/FluentFTP.CSharpExamples/DownloadManyFiles.cs 创建了一个 PoC,它正确地做到了:连接一次,然后下载文件。我感觉 FtpWebRequest
就是这种情况。我不明白 KeepAlive
及其作用。也许它重用了 TCP 连接,这本身就是一件好事,但它使用 TCP 连接在每个请求上登录。
有谁知道 FtpWebRequest
是否可以做到这一点,而不是像 Fluent FTP API 那样在每个新请求上登录?我错过了什么吗?
可在此处查看 FTP 日志示例
FTP 是 FileZilla Server 0.9.60 测试版。
似乎 FTP 连接重用未在 .NET Core 中实现:
https://github.com/dotnet/runtime/issues/23256
而作为 *WebRequest
API is actually obsolete,它可能永远不会。
使用 .NET 框架,它按预期工作:
我正在尝试通过一个打开的连接将多个文件下载到内存中。
我从该文档中得知:https://docs.microsoft.com/en-us/dotnet/api/system.net.ftpwebrequest.keepalive – FtpWebRequest
默认 KeepAlive
为真。
if the connection to the server should not be destroyed; otherwise, false. The default value is true.
我创建了这段代码:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
namespace ConsoleApp23
{
class Program
{
static void Main(string[] args)
{
String[] files = FTPListTree("ftp://server.com", "user", "password");
for (int i = 0; i <= files.Count() - 1; i++)
{
string path = files[i].ToString();
var request = (FtpWebRequest)WebRequest.Create(path);
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.Credentials = new NetworkCredential("user", "password");
request.Timeout = 100000;
request.KeepAlive = true;
request.ConnectionGroupName = "DownloadFilesGroup";
request.ServicePoint.ConnectionLimit = 8;
using (var response = (FtpWebResponse)request.GetResponse())
{
using (var stream = response.GetResponseStream())
{
var ms = new MemoryStream();
stream.CopyTo(ms);
var a = ms.ToArray();
string ss = Encoding.UTF8.GetString(a);
Console.WriteLine(ss);
}
}
}
}
public static String[] FTPListTree(String ftpUri, String user, String pass)
{
try
{
List<String> files = new List<String>();
Queue<String> folders = new Queue<String>();
folders.Enqueue(ftpUri);
while (folders.Count > 0)
{
String fld = folders.Dequeue();
List<String> newFiles = new List<String>();
FtpWebRequest ftp = (FtpWebRequest)FtpWebRequest.Create(fld);
ftp.Timeout = 20000;
ftp.Credentials = new NetworkCredential(user, pass);
ftp.Method = WebRequestMethods.Ftp.ListDirectory;
using (StreamReader resp = new StreamReader(ftp.GetResponse().GetResponseStream()))
{
String line = resp.ReadLine();
while (line != null)
{
newFiles.Add(line.Trim());
line = resp.ReadLine();
}
}
ftp = (FtpWebRequest)FtpWebRequest.Create(fld);
ftp.Timeout = 20000;
ftp.Credentials = new NetworkCredential(user, pass);
ftp.Method = WebRequestMethods.Ftp.ListDirectory;
using (StreamReader resp = new StreamReader(ftp.GetResponse().GetResponseStream()))
{
String line = resp.ReadLine();
while (line != null)
{
if (!Path.HasExtension(line))
{
String dir = newFiles.First(x => line.EndsWith(x));
newFiles.Remove(dir);
folders.Enqueue(fld + dir + "/");
}
line = resp.ReadLine();
}
}
files.AddRange(from f in newFiles select fld + f);
}
return files.ToArray();
}
catch (Exception e)
{
throw;
}
}
}
}
这是处理的正确方法吗?我似乎找不到任何关于如果处理 response
或响应流,将关闭控制连接,keepalive 将保持打开状态的文档。
有什么方法可以在 运行 时记录下来,以便我可以看到 FTP 调用?我自己无法访问 FTP 服务器。
更新
我实际上已经用测试 FTP 和上面的代码对此进行了测试,即使它有 KeepAlive=true
,它也会在每个请求上使用新连接。我用 Fluent API: https://github.com/robinrodricks/FluentFTP/blob/master/FluentFTP.CSharpExamples/DownloadManyFiles.cs 创建了一个 PoC,它正确地做到了:连接一次,然后下载文件。我感觉 FtpWebRequest
就是这种情况。我不明白 KeepAlive
及其作用。也许它重用了 TCP 连接,这本身就是一件好事,但它使用 TCP 连接在每个请求上登录。
有谁知道 FtpWebRequest
是否可以做到这一点,而不是像 Fluent FTP API 那样在每个新请求上登录?我错过了什么吗?
可在此处查看 FTP 日志示例
FTP 是 FileZilla Server 0.9.60 测试版。
似乎 FTP 连接重用未在 .NET Core 中实现: https://github.com/dotnet/runtime/issues/23256
而作为 *WebRequest
API is actually obsolete,它可能永远不会。
使用 .NET 框架,它按预期工作: