C# mReader(远程文件流)) { 使用(var csv=新的CsvReader(读卡器)) { /* //CSV解析示例: var记录=新列表(); csv.Read(); csv.ReadHeader(); 而(csv.Read()) { var记录=新的Foo { Id=csv.GetField(“Id”), Name=csv.GetField(“名称”) }; 记录。添加(记录); } */ } } } } 最后{ sftp.Disconnect(); } } }

C# mReader(远程文件流)) { 使用(var csv=新的CsvReader(读卡器)) { /* //CSV解析示例: var记录=新列表(); csv.Read(); csv.ReadHeader(); 而(csv.Read()) { var记录=新的Foo { Id=csv.GetField(“Id”), Name=csv.GetField(“名称”) }; 记录。添加(记录); } */ } } } } 最后{ sftp.Disconnect(); } } },c#,C#,使用SftpClient池的修改版本 看 池的实施借用自: // ///从[How to:通过使用 ///[购物袋](https://docs.microsoft.com/en-us/dotnet/standard/collections/thread-safe/how-to-create-an-object-pool). /// /// 公共类对象池:IDisposable 其中T:IDisposable { 私有只读函数对象生成器; 私有只读ConcurrentBag_对象; 公共对象池

使用SftpClient池的修改版本

池的实施借用自:

//
///从[How to:通过使用
///[购物袋](https://docs.microsoft.com/en-us/dotnet/standard/collections/thread-safe/how-to-create-an-object-pool).
/// 
/// 
公共类对象池:IDisposable
其中T:IDisposable
{
私有只读函数对象生成器;
私有只读ConcurrentBag_对象;
公共对象池(Func对象生成器)
{
_objectGenerator=objectGenerator??抛出新ArgumentNullException(nameof(objectGenerator));
_对象=新的ConcurrentBag();
}
公共空间处置()
{
while(_objects.TryTake(out var项))
{
item.Dispose();
}
}
公共T GetObject()
{
返回_objects.TryTake(out var item)?item:_objectGenerator();
}
公共对象(T项)
{
_对象。添加(项);
}
}
最简单的基于池的实现(它不关心异常处理、重试策略):

内部类SFTPClient
{
私有只读对象池\u对象池;
公共SFTPClient(凭据)
{
_objectPool=新的objectPool(()=>
{
var client=新的SftpClient(credentials.host、credentials.username、credentials.password);
client.Connect();
返回客户;
});
}
public void GetDirectoryList()
{
var client=_objectPool.GetObject();
尝试
{
//client.ListDirectory()。。
}
最后
{
如果(客户端已断开连接)
{
_objectPool.PutObject(客户端);
}
}
}
公共异步任务ProcessRemoteFileAsync()
{
var filepath=新列表();
//正在初始化文件路径。。
var tasks=文件路径
.Select(f=>ParseRemoteFileAsync(f))
.ToArray();
var results=await Task.WhenAll(tasks).ConfigureAwait(false);
//遍历结果。。
}
公共任务ParseRemoteFileAsync(字符串文件路径)
{
var client=_objectPool.GetObject();
尝试
{
使用(var remoteFileStream=client.OpenRead(filePath))
{
使用(var reader=newstreamreader(remoteFileStream))
{
使用(var csv=新的CsvReader(读卡器))
{
// ..
}
}
返回Task.FromResult(新文件内容());
}
}
最后
{
如果(客户端已断开连接)
{
_objectPool.PutObject(客户端);
}
}
}
}


您需要使用内存流。然后从SFTP填充内存流。我会编写自己的代码来读取csv而不是使用CSVHelper。使用内存流而不是将文件保存到本地然后打开它有什么缺点吗?:)不会。内存流将更有效,因为您只需执行一个步骤而不是两个步骤(写入文件,然后读取文件)。内存流相当于流编写器或流读取器。@jdweng我想异步执行此方法。可能吗?因为许多国家有很多目录,我希望每个国家都能下载文件并并行解析CSV。一些服务器限制来自同一IP的连接数,因此可能无法实现。您需要使用内存流。然后从SFTP填充内存流。我会编写自己的代码来读取csv而不是使用CSVHelper。使用内存流而不是将文件保存到本地然后打开它有什么缺点吗?:)不会。内存流将更有效,因为您只需执行一个步骤而不是两个步骤(写入文件,然后读取文件)。内存流相当于流编写器或流读取器。@jdweng我想异步执行此方法。可能吗?因为有很多国家的目录,我希望每个国家下载文件并并行解析CSV。一些服务器限制来自同一IP的连接数,因此可能无法实现。我是否可以将ReadAndParseCSV逻辑放在自己的函数中,并在using csvreader中调用它?是的,您可以将其移动到单独的方法。我希望异步执行此方法。可能吗?因为有许多国家的目录,我希望每个国家下载文件并解析CSV并行。这可能吗?我添加了多文件处理的示例,它应该可以帮助您自己开始;)谢谢,有件事我很好奇。我得到了一个名为GetDirectoryListFromSFTP()的函数,它创建了到与ReadRemoteDirectory相同的SFTP的连接,是否可以在另一个文件夹中创建此连接->获取目录列表->关闭连接->打开连接
    public async Task ProcessRemoteFilesAsync()
    {
        var credentials = new Credentials("host", "username", "password");
        var filePaths = new List<string>();

        // initializing filePaths ..

        var tasks = filePaths
            .Select(f => ParseRemoteFileAsync(credentials, f))
            .ToArray();

        var results = await Task.WhenAll(tasks).ConfigureAwait(false);

        // traverse through results..
    }

    public async Task<FileContent> ParseRemoteFileAsync(Credentials credentials, string filePath)
    {
        using (var sftp = new SftpClient(credentials.host, credentials.username, credentials.password))
        {
            sftp.Connect();

            try
            {
                using (var remoteFileStream = sftp.OpenRead(filePath))
                {
                    using (var reader = new StreamReader(remoteFileStream))
                    {
                        using (var csv = new CsvReader(reader))
                        {
                            /*
                            // Example of CSV parsing:
                            var records = new List<Foo>();
                            csv.Read();
                            csv.ReadHeader();
                            while (csv.Read())
                            {
                                var record = new Foo
                                {
                                    Id = csv.GetField<int>("Id"),
                                    Name = csv.GetField("Name")
                                };
                                records.Add(record);
                            }
                            */
                        }
                    }
                }
            }
            finally {
                sftp.Disconnect();
            }
        }
    }
/// <summary>
///     Implementation borrowed from [How to: Create an Object Pool by Using a
///     ConcurrentBag](https://docs.microsoft.com/en-us/dotnet/standard/collections/thread-safe/how-to-create-an-object-pool).
/// </summary>
/// <typeparam name="T"></typeparam>
public class ObjectPool<T> : IDisposable
    where T : IDisposable
{
    private readonly Func<T> _objectGenerator;
    private readonly ConcurrentBag<T> _objects;

    public ObjectPool(Func<T> objectGenerator)
    {
        _objectGenerator = objectGenerator ?? throw new ArgumentNullException(nameof(objectGenerator));
        _objects = new ConcurrentBag<T>();
    }

    public void Dispose()
    {
        while (_objects.TryTake(out var item))
        {
            item.Dispose();
        }
    }

    public T GetObject()
    {
        return _objects.TryTake(out var item) ? item : _objectGenerator();
    }

    public void PutObject(T item)
    {
        _objects.Add(item);
    }
}
internal class SftpclientTest
{
    private readonly ObjectPool<SftpClient> _objectPool;


    public SftpclientTest(Credentials credentials)
    {
        _objectPool = new ObjectPool<SftpClient>(() =>
        {
            var client = new SftpClient(credentials.host, credentials.username, credentials.password);
            client.Connect();

            return client;
        });
    }


    public void GetDirectoryList()
    {
        var client = _objectPool.GetObject();

        try
        {
            // client.ListDirectory() ..
        }
        finally
        {
            if (client.IsConnected)
            {
                _objectPool.PutObject(client);
            }
        }
    }


    public async Task ProcessRemoteFilesAsync()
    {
        var filePaths = new List<string>();

        // initializing filePaths ..

        var tasks = filePaths
            .Select(f => ParseRemoteFileAsync(f))
            .ToArray();

        var results = await Task.WhenAll(tasks).ConfigureAwait(false);

        // traverse through results..
    }

    public Task<FileContent> ParseRemoteFileAsync(string filePath)
    {
        var client = _objectPool.GetObject();

        try
        {
            using (var remoteFileStream = client.OpenRead(filePath))
            {
                using (var reader = new StreamReader(remoteFileStream))
                {
                    using (var csv = new CsvReader(reader))
                    {
                        // ..
                    }
                }

                return Task.FromResult(new FileContent());
            }
        }
        finally
        {
            if (client.IsConnected)
            {
                _objectPool.PutObject(client);
            }
        }
    }
}