<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Ftp基礎(chǔ)(五):.NetCore中使用Ftp的建議(FluentFTP)

      ??上一篇說道C#使用FluentFTP來簡(jiǎn)單的連接使用Ftp,本篇是個(gè)人在.NetCore中使用Ftp的建議(可能有點(diǎn)啰嗦):

      ??1、為Ftp的配置創(chuàng)建基類

      ??在開發(fā)過程中,我們?nèi)绻褂肍tp,往往需要這幾個(gè)信息:??

          Host:Ftp地址
          Port:端口號(hào)
          User:用戶名
          Password:密碼
          WorkingDirectory:工作目錄,如果你希望整個(gè)Ftp只給一個(gè)系統(tǒng)使用,可以不用,直接使用根目錄
          Mode:模式:主動(dòng)模式、被動(dòng)模式

         ?除了上述幾個(gè)信息,我們?cè)陂_發(fā)過程中可能還會(huì)有其它配置,比如我們的業(yè)務(wù)配置,也有可能是Ftp的配置,但是這些配置都和具體場(chǎng)景有關(guān)。

      ??而這些信息,可能來自我們的配置文件,也可能來自數(shù)據(jù)庫(kù)配置,還可能來自我們UI的輸入,所以,我們應(yīng)該給Ftp的配置一個(gè)基類(也可以是抽象類),比如:

          public class FtpOptions
          {
              /// <summary>
              /// Ftp地址,默認(rèn)localhost
              /// </summary>
              public string Host { get; set; } = "localhost";
              /// <summary>
              /// Ftp端口號(hào),默認(rèn)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>
              /// 是否主動(dòng)模式
              /// </summary>
              public bool Active { get; set; }
          }

      ??這樣,當(dāng)我們有一些特定需求的時(shí)候,可以繼承這個(gè)基類,比如我們下載的時(shí)候,可能需要限速,那么我們可以創(chuàng)建這樣的配置類:

          public class DownloadFtpOptions : FtpOptions
          {
              /// <summary>
              /// 下載限速(字節(jié))
              /// </summary>
              public long Bytes { get; set; }
          }

      ??再比如,當(dāng)我們使用Ftp來作為兩個(gè)系統(tǒng)之間的信息傳遞的媒介時(shí),比如??

          A系統(tǒng)上傳文件到Ftp指定的目錄,那么需要的配置是:Ftp基本配置、上傳目錄
          B系統(tǒng)定時(shí)掃描指定的目錄來下載文件,那么需要的配置是:Ftp基本配置、掃描目錄、掃描時(shí)間間隔

      ??那么我們可以分別為A\B系統(tǒng)創(chuàng)建這么兩個(gè)配置類:??

          public class UploadFtpOptions : FtpOptions
          {
              /// <summary>
              /// 上傳文件的目錄
              /// </summary>
              public string Path { get; set; }
          }
          public class ScanFtpOptions : FtpOptions
          {
              /// <summary>
              /// 掃描時(shí)間間隔
              /// </summary>
              public int Interval { get; set; }
              /// <summary>
              /// 掃描文件的目錄
              /// </summary>
              public string Path { get; set; }
          }

      ??2、通過一個(gè)方法來獲取FtpClient或者AsyncFtpClient

      ??有了配置,接下來我們需要使用,利用FluentFTP來操作Ftp的話,我們需要?jiǎng)?chuàng)建FtpClient或者AsyncFtpClient,這個(gè)時(shí)候,我們應(yīng)該通過一個(gè)通用的方法來創(chuàng)建,而這個(gè)方法,可以是基類的一個(gè)公共方法,也可以是基類的一個(gè)拓展方法:

      ??使用基類的公共方法,可以使用virtual修飾,后續(xù)子類有需要,可以自定義重寫

          public class FtpOptions
          {
              //省略屬性...
      
              /// <summary>
              /// 創(chuàng)建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>
              /// 創(chuàng)建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>
              /// 創(chuàng)建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>
              /// 創(chuàng)建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;
              }
          }

      ??兩種方式各有各的優(yōu)劣,具體開發(fā)再選擇吧。

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

      ??在開發(fā)過程中,應(yīng)該有些同學(xué)第一反應(yīng)就是要把FtpClient封裝成類似HttpClient的方式去使用吧,先封裝個(gè)工廠,然后使用它來創(chuàng)建FtpClient,其實(shí)個(gè)人不推薦這種做法,因?yàn)樗@么做屬于對(duì)Ftp形成了強(qiáng)依賴。既然使用了.NetCore,那么我們很多時(shí)候應(yīng)該面向接口開發(fā),特別是針對(duì)Ftp這類第三方庫(kù)時(shí),我們應(yīng)該盡可能對(duì)它形成弱依賴,而不能說不使用它,我們系統(tǒng)就玩不轉(zhuǎn)了吧。

      ??其實(shí),這就需要我們能對(duì)自己系統(tǒng)的業(yè)務(wù)進(jìn)行區(qū)分,比如,當(dāng)我們只是想存儲(chǔ)文件時(shí),我們可以創(chuàng)建這么一個(gè)接口:??

          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的操作只需要實(shí)現(xiàn)這個(gè)接口然后把接口注入就可以了,這樣我們哪天不想使用Ftp存儲(chǔ)文件,只需要使用其它的工具實(shí)現(xiàn)這個(gè)就可以了。

       ??:你可能回想為什么沒有目錄的操作?這個(gè)是因?yàn)槟夸洸痪邆溥@個(gè)業(yè)務(wù)的共性,存的是文件,不是目錄,而且哪天如果要緩存MongoGridFS、某些對(duì)象存儲(chǔ)方案時(shí),可能根本就沒有目錄的概念,當(dāng)然我們也可以在這個(gè)接口上加上目錄的操作,如果不支持目錄操作,我們只需要空實(shí)現(xiàn)就好了

      ??再比如,如果我們需要掃描Ftp的某個(gè)目錄,我們可以創(chuàng)建這么一個(gè)接口:??

          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來實(shí)現(xiàn) 這個(gè)接口就可以了,后續(xù)如果我們掃描的是本地的目錄、Cifs/Smb等其它的方案,我們只需要對(duì)應(yīng)的實(shí)現(xiàn)就可以了

      ??

      ??總結(jié)

      ??Ftp很早就出現(xiàn)了,優(yōu)劣我們暫且不評(píng)論,以前系統(tǒng)用的很多,但是現(xiàn)在不一樣了,特別是互聯(lián)網(wǎng)項(xiàng)目,幾乎都不用的,而取代它的方案,現(xiàn)在還是有很多可以選擇,比如用的多的還有Cifs/Smb,所以我們?cè)陂_發(fā)時(shí),盡量不要對(duì)這種工具形成強(qiáng)依賴,如果確實(shí)避不開,我們應(yīng)該要考慮把它所有操作自己做個(gè)封裝,封裝在一個(gè)類中,后續(xù)如果要替代,我們也可以很方便平穩(wěn)的過渡。

       

      posted @ 2023-12-30 19:03  沒有星星的夏季  閱讀(1678)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 国产视色精品亚洲一区二区 | 午夜福利精品国产二区| 日本乱码在线看亚洲乱码| 农村妇女野外一区二区视频| 噜噜噜亚洲色成人网站∨| 97免费人妻在线视频| 亚洲国产精品男人的天堂| 精品人妻少妇嫩草av专区| 久久一本人碰碰人碰| 免费AV片在线观看网址| 国产精品一二二区视在线| 国产午夜亚洲精品国产成人| 日韩精品一区二区三区激情视频 | 日韩a∨精品日韩在线观看 | 麻豆妓女爽爽一区二区三| 人妻少妇无码精品视频区| 日韩高清国产中文字幕| 精品国产免费人成网站| 久久国产精品波多野结衣| 视频一区视频二区亚洲视频| 在线观看亚洲欧美日本| 日本三级香港三级三级人妇久| 久久精品免视看成人国产| 青青草原国产AV福利网站| 丘北县| 亚洲狼人久久伊人久久伊| 久久国产免费观看精品3| 使劲快高潮了国语对白在线| 大尺度国产一区二区视频| 天天躁日日躁狠狠躁2018| 婷婷成人丁香五月综合激情| 亚洲熟女乱色综一区二区| 欧美成人精品手机在线| 最新国产在线拍揄自揄视频| 97超级碰碰碰久久久久| 亚洲V天堂V手机在线| 波多野结衣乳喷高潮视频| 久久精品国产九一九九九| 一本av高清一区二区三区| 亚洲精品国产自在久久| 熟女女同亚洲女同中文字幕|