首页 > 其他分享 >Ftp基础(五):.NetCore中使用Ftp的建议(FluentFTP)

Ftp基础(五):.NetCore中使用Ftp的建议(FluentFTP)

时间:2023-12-30 19:12:09浏览次数:35  
标签:Ftp ftpOptions string NetCore Port FluentFTP public ftpClient

  上一篇说道C#使用FluentFTP来简单的连接使用Ftp,本篇是个人在.NetCore中使用Ftp的建议(可能有点啰嗦):

  1、为Ftp的配置创建基类

  在开发过程中,我们如果要使用Ftp,往往需要这几个信息:  

    Host:Ftp地址
    Port:端口号
    User:用户名
    Password:密码
    WorkingDirectory:工作目录,如果你希望整个Ftp只给一个系统使用,可以不用,直接使用根目录
    Mode:模式:主动模式、被动模式

    除了上述几个信息,我们在开发过程中可能还会有其它配置,比如我们的业务配置,也有可能是Ftp的配置,但是这些配置都和具体场景有关。

  而这些信息,可能来自我们的配置文件,也可能来自数据库配置,还可能来自我们UI的输入,所以,我们应该给Ftp的配置一个基类(也可以是抽象类),比如:

    public class FtpOptions
    {
        /// <summary>
        /// Ftp地址,默认localhost
        /// </summary>
        public string Host { get; set; } = "localhost";
        /// <summary>
        /// Ftp端口号,默认21
        /// </summary>
        public int Port { get; set; } = 21;
        /// <summary>
        /// User
        /// </summary>
        public string User { get; set; }
        /// <summary>
        /// Password
        /// </summary>
        public string Password { get; set; }
        /// <summary>
        /// 根目录
        /// </summary>
        public string WorkingDirectory { get; set; }
        /// <summary>
        /// 是否主动模式
        /// </summary>
        public bool Active { get; set; }
    }

  这样,当我们有一些特定需求的时候,可以继承这个基类,比如我们下载的时候,可能需要限速,那么我们可以创建这样的配置类:

    public class DownloadFtpOptions : FtpOptions
    {
        /// <summary>
        /// 下载限速(字节)
        /// </summary>
        public long Bytes { get; set; }
    }

  再比如,当我们使用Ftp来作为两个系统之间的信息传递的媒介时,比如  

    A系统上传文件到Ftp指定的目录,那么需要的配置是:Ftp基本配置、上传目录
    B系统定时扫描指定的目录来下载文件,那么需要的配置是:Ftp基本配置、扫描目录、扫描时间间隔

  那么我们可以分别为A\B系统创建这么两个配置类:  

    public class UploadFtpOptions : FtpOptions
    {
        /// <summary>
        /// 上传文件的目录
        /// </summary>
        public string Path { get; set; }
    }
    public class ScanFtpOptions : FtpOptions
    {
        /// <summary>
        /// 扫描时间间隔
        /// </summary>
        public int Interval { get; set; }
        /// <summary>
        /// 扫描文件的目录
        /// </summary>
        public string Path { get; set; }
    }

  2、通过一个方法来获取FtpClient或者AsyncFtpClient

  有了配置,接下来我们需要使用,利用FluentFTP来操作Ftp的话,我们需要创建FtpClient或者AsyncFtpClient,这个时候,我们应该通过一个通用的方法来创建,而这个方法,可以是基类的一个公共方法,也可以是基类的一个拓展方法:

  使用基类的公共方法,可以使用virtual修饰,后续子类有需要,可以自定义重写

    public class FtpOptions
    {
        //省略属性...

        /// <summary>
        /// 创建ftp连接
        /// </summary>
        /// <returns></returns>
        public virtual FtpClient GetFtpClient()
        {
            var ftpClient = new FtpClient(Host);
            if (Port > 0)
            {
                ftpClient.Port = Port;
            }
            if (!string.IsNullOrEmpty(User) && !string.IsNullOrEmpty(Password))
            {
                ftpClient.Credentials = new NetworkCredential(User, Password);
            }
            ftpClient.Encoding = Encoding.UTF8;
            ftpClient.Config.DataConnectionType = Active ? FtpDataConnectionType.AutoActive : FtpDataConnectionType.AutoPassive;
            ftpClient.Connect();

            ftpClient.CreateDirectory(WorkingDirectory);
            ftpClient.SetWorkingDirectory(WorkingDirectory);
            return ftpClient;
        }
        /// <summary>
        /// 创建ftp连接(异步)
        /// </summary>
        /// <returns></returns>
        public virtual async Task<AsyncFtpClient> GetAsyncFtpClient()
        {
            var ftpClient = new AsyncFtpClient(Host);
            if (Port > 0)
            {
                ftpClient.Port = Port;
            }
            if (!string.IsNullOrEmpty(User) && !string.IsNullOrEmpty(Password))
            {
                ftpClient.Credentials = new NetworkCredential(User, Password);
            }
            ftpClient.Encoding = Encoding.UTF8;
            ftpClient.Config.DataConnectionType = Active ? FtpDataConnectionType.AutoActive : FtpDataConnectionType.AutoPassive;
            await ftpClient.Connect();

            await ftpClient.CreateDirectory(WorkingDirectory);
            await ftpClient.SetWorkingDirectory(WorkingDirectory);
            return ftpClient;
        }
    }

  使用基类的拓展方法:

    public static class FtpOptionsExtensions
    {
        /// <summary>
        /// 创建ftp连接
        /// </summary>
        /// <param name="klarfDiscoveryOptions"></param>
        /// <returns></returns>
        public static FtpClient GetFtpClient(this FtpOptions ftpOptions)
        {
            var ftpClient = new FtpClient(ftpOptions.Host);
            if (ftpOptions.Port > 0)
            {
                ftpClient.Port = ftpOptions.Port;
            }
            if (!string.IsNullOrEmpty(ftpOptions.User) && !string.IsNullOrEmpty(ftpOptions.Password))
            {
                ftpClient.Credentials = new NetworkCredential(ftpOptions.User, ftpOptions.Password);
            }
            ftpClient.Encoding = Encoding.UTF8;
            ftpClient.Config.DataConnectionType = ftpOptions.Active ? FtpDataConnectionType.AutoActive : FtpDataConnectionType.AutoPassive;
            ftpClient.Connect();

            ftpClient.CreateDirectory(ftpOptions.WorkingDirectory);
            ftpClient.SetWorkingDirectory(ftpOptions.WorkingDirectory);
            return ftpClient;
        }
        /// <summary>
        /// 创建ftp连接(异步)
        /// </summary>
        /// <param name="klarfDiscoveryOptions"></param>
        /// <returns></returns>
        public static async Task<AsyncFtpClient> GetAsyncFtpClient(this FtpOptions ftpOptions)
        {
            var ftpClient = new AsyncFtpClient(ftpOptions.Host);
            if (ftpOptions.Port > 0)
            {
                ftpClient.Port = ftpOptions.Port;
            }
            if (!string.IsNullOrEmpty(ftpOptions.User) && !string.IsNullOrEmpty(ftpOptions.Password))
            {
                ftpClient.Credentials = new NetworkCredential(ftpOptions.User, ftpOptions.Password);
            }
            ftpClient.Encoding = Encoding.UTF8;
            ftpClient.Config.DataConnectionType = ftpOptions.Active ? FtpDataConnectionType.AutoActive : FtpDataConnectionType.AutoPassive;
            await ftpClient.Connect();

            await ftpClient.CreateDirectory(ftpOptions.WorkingDirectory);
            await ftpClient.SetWorkingDirectory(ftpOptions.WorkingDirectory);
            return ftpClient;
        }
    }

  两种方式各有各的优劣,具体开发再选择吧。

  3、面向接口来使用Ftp或者FluentFTP

  在开发过程中,应该有些同学第一反应就是要把FtpClient封装成类似HttpClient的方式去使用吧,先封装个工厂,然后使用它来创建FtpClient,其实个人不推荐这种做法,因为它这么做属于对Ftp形成了强依赖。既然使用了.NetCore,那么我们很多时候应该面向接口开发,特别是针对Ftp这类第三方库时,我们应该尽可能对它形成弱依赖,而不能说不使用它,我们系统就玩不转了吧。

  其实,这就需要我们能对自己系统的业务进行区分,比如,当我们只是想存储文件时,我们可以创建这么一个接口:  

    public interface IFileStorage
    {
        /// <summary>
        /// 文件是否存在
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        Task<bool> FileExistsAsync(string fileName);
        /// <summary>
        /// 删除文件
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        Task DeleteFileAsync(string fileName);
        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="stream"></param>
        /// <returns></returns>
        Task UploadAsync(string fileName, Stream stream);
        /// <summary>
        /// 下载文件
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="stream"></param>
        /// <returns></returns>
        Task DownloadAsync(string fileName, Stream stream);
    }

  我们Ftp的操作只需要实现这个接口然后把接口注入就可以了,这样我们哪天不想使用Ftp存储文件,只需要使用其它的工具实现这个就可以了。

   :你可能回想为什么没有目录的操作?这个是因为目录不具备这个业务的共性,存的是文件,不是目录,而且哪天如果要缓存MongoGridFS、某些对象存储方案时,可能根本就没有目录的概念,当然我们也可以在这个接口上加上目录的操作,如果不支持目录操作,我们只需要空实现就好了

  再比如,如果我们需要扫描Ftp的某个目录,我们可以创建这么一个接口:  

    public interface IScanSource
    {
        /// <summary>
        /// 返回指定目录下的文件及目录
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        Task<ScanItem[]> List(string path);
        /// <summary>
        /// 下载文件
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="stream"></param>
        /// <returns></returns>
        Task DownloadAsync(string fileName, Stream stream);
    }
    public class ScanItem
    {
        /// <summary>
        /// 文件或者名称
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 是否是目录
        /// </summary>
        public bool IsDirectory { get; set; }
    }

   通用,我们只需要使用Ftp来实现 这个接口就可以了,后续如果我们扫描的是本地的目录、Cifs/Smb等其它的方案,我们只需要对应的实现就可以了

  

  总结

  Ftp很早就出现了,优劣我们暂且不评论,以前系统用的很多,但是现在不一样了,特别是互联网项目,几乎都不用的,而取代它的方案,现在还是有很多可以选择,比如用的多的还有Cifs/Smb,所以我们在开发时,尽量不要对这种工具形成强依赖,如果确实避不开,我们应该要考虑把它所有操作自己做个封装,封装在一个类中,后续如果要替代,我们也可以很方便平稳的过渡。

 

标签:Ftp,ftpOptions,string,NetCore,Port,FluentFTP,public,ftpClient
From: https://www.cnblogs.com/shanfeng1000/p/17883564.html

相关文章

  • 怎么使用FTP
    FTP服务器(FileTransferProtocolServer)是在互联网上提供文件存储和访问服务的计算机,它们依照FTP协议提供服务。FTP是FileTransferProtocol的缩写,即文件传输协议,是一种基于TCP的协议,采用客户/服务器模式。通过FTP协议,用户可以在FTP服务器中进行文件的上传或下载等操作。简单地说......
  • linux下java调用netcore程序
    代码备份仅供参考自述文件#JavaCallCSharpJavacallC#libbuildwith.NETCORE2.0viaC++aswraperThecodeisbasedon[examplefromcoreCLR](https://github.com/dotnet/coreclr/tree/master/src/coreclr/hosts/unixcoreruncommon)JavausingJNItocallC++......
  • Linux下netcore调用java代码
    代码备份,仅供参考自述文件#CSharpCallJavaC#invokeJavaviaC++asawraper.C#invokeC++viaP/invoke.C++startsaJVMtoruntheJavacode.C#codeshouldbecompiledin.NETcore2.0YoushouldedittheMakefiletosetthePathofJavaSDKexpor......
  • Pure-ftpd 安装
    Pure-FTPd是一款免费(BSD)的,安全的,高质量和符合标准的FTP服务器。侧重于运行效率和易用性。它提供了简单的答案,他满足了大众化的需求,包括普通用户以及主机供应商们。CentOS安装yuminstall-ypure-ftpd前提是配置了epel源配置修改#关闭AnonymousOnlysed-i's/^Anon......
  • NetCore高级系列文章04---async、await原理揭秘
    async、await本质上是C#提供的语法糖,编译器编译后是状态机的调用。先看如下的一段代码,要main方法中调用了三个await方法 将此dll进行反编译为4.0的代码如下: 可见到两个Main方法,也就是说我们在程序中Main方法上加了async关键词,编译器会编译成一个是异步的一个是非异步方法,程......
  • 用IIS搭建FTP服务器
    注意:经实测,IIS会限制传输速度,已经不推荐使用IIS来搭建,推荐使用FTP点击跳转:用FileZilla搭建FTP服务器目的通过FTP,让电脑和手机之间能够无线传输数据开启IIS功能快捷键win+s搜索控制面板打开点击程序,点击启用或关闭windows功能找到InternetInformationServices,勾选FTP服......
  • FTP服务器
    FTP服务器:如何把文件传到Ubuntu主机上?1.U盘拷贝2.网络传输- FTP- SFTP演示:使用FTP来传输文件。。。客户端FileZilla(Windows)服务器vsftpd(Ubuntu) ......
  • AspNetCore的单元测试
    一、单元测试项目如何创建VisualStudio新建项目,项目类型选择测试。 可以看到有许多选项,都大差不差。这里选择xUnit。项目名使用要测试的项目名加上“.Tests”后缀。二、进行单元测试首先明确测试对象,通常是针对一个类型进行测试,新建Test类,类名为测试对象的类名加上“Test......
  • Sftp日常使用(上传和下载)
    SftpSFTP是SecureFileTransferProtocol的缩写,安全文件传送协议。可以为传输文件提供一种安全的网络的加密方法。SFTP与FTP有着几乎一样的语法和功能。SFTP为SSH的其中一部分,是一种传输档案至Blogger伺服器的安全方式。其实在SSH软件包中,已经包含了一个叫作SFTP(SecureFileTr......
  • Windows下用rclone代替RaiDrive将ftp映射为本地盘
    Windows下用rclone代替RaiDrive将ftp映射为本地盘1.软件准备:nssm:官网下载地址:https://nssm.cc/downloadrclone:官网下载地址:https://rclone.org/downloads/WinFsp:官网下载地址:https://winfsp.dev/rel/2.使用:下载WinFsp,如我下载的是winfsp-2.0.23075.msi,下一步下......