C# FTP服务器 FTP客户端,文件上传下载

主要使用的软件是 HslCommunication 关于这个软件的本身,详细可以参考下面的地址:

github地址:https://github.com/dathlin/HslCommunication

官网:http://www.hsltechnology.cn

 

加群咨询学习信息:http://www.hslcommunication.cn/Cooperation 

在Visual Studio 中的NuGet管理器中可以下载安装,也可以直接在NuGet控制台输入下面的指令安装:

 

Install-Package HslCommunication

  

如果需要教程:Nuget安装教程:http://www.cnblogs.com/dathlin/p/7705014.html

组件的api地址:http://api.hslcommunication.cn

使用手册:http://www.hsltechnology.cn/Doc/HslCommunication

Demo下载地址:http://www.hsltechnology.cn/Home/Download

 

在开始之前,我们先来看看HslCommunication能干什么?

image

 

 

1. Demo快速体验


 

如果我们想快速搭建一个 FTP服务器, 然后在客户端进行收发文件操作的话,使用我们得 Demo程序 是非常快,并且简单的。我们先打开Demo得服务器

image

 然后我们在打开一个客户端,输入ip地址及端口号,然后点击 连接, 刷新 操作,我们可以看到,服务器的文件目录显示出来了

image

 然后在树形目录里选择右键菜单操作,可以下载,删除,重命名文件

image

 当然针对文件夹右键操作,有删除,重命名,批量下载,批量上传操作

image

 如果我们的 FTP服务器 运行在云服务器的话,相关端口的权限得放行,不然无法通信的,除了主服务器端口之外,还有一个用于上传,下载,获取文件列表时使用的临时端口, 这个临时端口是随机的,不过我们可以在 Demo 程序里指定。

image

 

 

 

引用库


 

 

using HslCommunication;
using HslCommunication.Core;
using HslCommunication.Enthernet.Ftp;

  

服务器代码实现


 

服务器端写代码是非常容易的,下面的代码使用了更多的功能,所以稍微复杂一点,实际情况可以自己裁减

    class Program
    {
        static void Main( string[] args )
        {
            HslCommunication.Enthernet.Ftp.FtpServer ftpServer = new HslCommunication.Enthernet.Ftp.FtpServer( );
            ftpServer.CurrentDirectory = @"E:\Software\HslCommunicationDemo\";  // 遍历的路径
            ftpServer.AllowAnonymous = true;       // 允许匿名用户登录
            ftpServer.DownloadOnly = false;        // 如果只允许遍历和下载,设置为true,安全性高
            // ftpServer.SetPasvPortRange( "7000-8000" );   // 如果要设置随机的端口范围

            // 自定义的账户检查,如果不绑定该事件,就是只使用匿名登录
            ftpServer.CheckAccountFunction = new Func<string, string, HslCommunication.Enthernet.Ftp.FtpSession, OperateResult>( ( name, pwd, session ) =>
            {
                // session.CanEdit = false;          // 如果要控制某个会话没有上传和删除的权限,设置会话的该属性
                if (name == "admin" && pwd == "123456") return OperateResult.CreateSuccessResult( );
                return new OperateResult( 500, "user account or password wrong" ); // 不允许登录返回的信息
            } );

            try
            {
                ftpServer.ServerStart( Convert.ToInt32( "12345" ) );
            }
            catch (Exception ex)
            {
                Console.WriteLine( "Server Start failed: " + ex.ToString( ) );
            }

            Console.ReadLine( );
        }
    }

  

客户端代码实现


 

 

实例化操作

            HslCommunication.Enthernet.Ftp.FtpClient ftpClient = new HslCommunication.Enthernet.Ftp.FtpClient( );
            ftpClient.IpAddress = "127.0.0.1";
            ftpClient.Port = 12345;
            //ftpClient.Username = "admin";   // 匿名的话,用户名密码,不用输入
            //ftpClient.Password = "12345";

  

遍历指定目录的文件夹名称及文件列表

            Console.WriteLine( "List files..." );
            OperateResult<HslCommunication.Enthernet.Ftp.FtpFileItem[]> list = ftpClient.ListFiles( "/" );   // 如果其它目录就是 /Files/
            if (list.IsSuccess)
            {
                for (int i = 0; i < list.Content.Length; i++)
                {
                    HslCommunication.Enthernet.Ftp.FtpFileItem ftpFileItem = list.Content[i];
                    if (ftpFileItem.IsDirectory)
                    {
                        Console.WriteLine( "Path: " + ftpFileItem.Name );
                    }
                    else
                    {
                        Console.WriteLine( "File: " + ftpFileItem.Name + "   Size: " + ftpFileItem.Size  + "   Time: " + ftpFileItem.CreateTime );
                    }
                }
            }

  

下载一个文件

            // 第一个参数是FTP文件服务器的路径,第二个参数是本地存储的路径
            OperateResult result = ftpClient.DownloadFile( "FtpFiles/secs_f.png", @"E:\Software\HslCommunicationDemo\FtpFiles\secs_f.png" );
            if (result.IsSuccess)
            {
                Console.WriteLine( "文件下载成功" );
            }
            else
            {
                Console.WriteLine( "文件下载失败: " + result.Message );
            }

  

如果想要支持进度报告的话,代码如下

        static void Main( string[] args )
        {
            HslCommunication.Enthernet.Ftp.FtpClient ftpClient = new HslCommunication.Enthernet.Ftp.FtpClient( );
            ftpClient.IpAddress = "127.0.0.1";
            ftpClient.Port = 12345;
            //ftpClient.Username = "admin";   // 匿名的话,用户名密码,不用输入
            //ftpClient.Password = "12345";

            Console.WriteLine( "download file..." );

            // 第一个参数是FTP文件服务器的路径,第二个参数是本地存储的路径
            OperateResult result = ftpClient.DownloadFile( "FtpFiles/secs_f.png", @"E:\Software\HslCommunicationDemo\FtpFiles\secs_f.png", ReportDownloadProgress
                );
            if (result.IsSuccess)
            {
                Console.WriteLine( "文件下载成功" );
            }
            else
            {
                Console.WriteLine( "文件下载失败: " + result.Message );
            }



            Console.ReadLine( );
        }

        // 这里方法传入下载的参数,已下载字节数,总字节数
        private static void ReportDownloadProgress( long already, long total )
        {
            Console.WriteLine( "Already Bytes: " + already + "  Total: " + total + "   Percent: " + (already * 100 / total) + "%" );
        }

  

上传一个文件

            // 第一个参数是本地文件路径,第二个参数是FTP服务器存储的路径
            OperateResult result = ftpClient.UploadFile( @"E:\Software\HslRedisDesktop\yudian.png", "/yudian.png" );
            if (result.IsSuccess)
            {
                Console.WriteLine( "文件上传成功" );
            }
            else
            {
                Console.WriteLine( "文件上传失败: " + result.Message );
            }

  上传文件的功能也是支持进度报告的,这里尝试另一个写法,使用匿名委托 + Lamda表达式实现

            // 第一个参数是本地文件路径,第二个参数是FTP服务器存储的路径
            OperateResult result = ftpClient.UploadFile( @"E:\Software\HslRedisDesktop\yudian.png", "/yudian.png",
                new Action<long, long>( ( already, total ) =>
                {
                    Console.WriteLine( "Already Bytes: " + already + "  Total: " + total + "   Percent: " + (already * 100 / total) + "%" );
                } ) );
            if (result.IsSuccess)
            {
                Console.WriteLine( "文件上传成功" );
            }
            else
            {
                Console.WriteLine( "文件上传失败: " + result.Message );
            }

  

删除一个文件

            // 参数是原FTP服务器存储的路径, 新的文件名,前者需要带路径
            OperateResult result = ftpClient.RenameFile( "/secs_f.png", "secs_f2.png" );
            if (result.IsSuccess)
            {
                Console.WriteLine( "重命名文件成功" );
            }
            else
            {
                Console.WriteLine( "重命名文件失败: " + result.Message );
            }

  

重命名文件夹

            // 旧的路径和新的路径 例如  /A/testC     testD
            OperateResult result = ftpClient.RenameFolder( "testC", "testA" );
            if (result.IsSuccess)
            {
                Console.WriteLine( "重命名目录成功" );
            }
            else
            {
                Console.WriteLine( "重命名目录失败: " + result.Message );
            }

  

删除路径

            OperateResult result = ftpClient.DeleteDirectory( "testA/AA/" );
            if (result.IsSuccess)
            {
                Console.WriteLine( "目录删除成功" );
            }
            else
            {
                Console.WriteLine( "目录删除失败: " + result.Message );
            }

  

一个winform的复杂例子,后台线程下载,更新进度,带取消按钮

        private HslCancelToken downloadCacel = null;                      // 取消令牌很关键
        private void DownloadFileExample( )
        {
            button_download.Enabled = false;                              // 下载按钮禁止,打开取消下载按钮
            button_download_cancel.Enabled = true;
            label15.Text = "Start downloading...";
            downloadCacel = new HslCancelToken( );                        // 取消令牌实例化
            ThreadPool.QueueUserWorkItem( new WaitCallback( ThreadPoolDownloadFile ), "/secs_f2.png" );
        }

        // 点击下载取消的按钮,取消的令牌设置为 True
        private void button_download_cancel_Click( object sender, EventArgs e )
        {
            if (downloadCacel != null) downloadCacel.IsCancelled = true;
        }

        private void ThreadPoolDownloadFile( object state )
        {
            string fileName = state as string;

            DateTime downloadStartTime = DateTime.Now;
            OperateResult result = ftpClient.DownloadFile(
                    fileName,                                        // 文件在服务器上保存的名称,举例123.txt
                    "D:\\secs_f2.png",                               // 下载后在文本保存的路径,也可以直接下载到 MemoryStream 的数据流中, 或是手动选择存储路径
                    DownloadReportProgress,                          // 文件下载的时候的进度报告,友好的提示下载进度信息
                    downloadCacel                                    // 下载取消的令牌
                    );

            // 切换窗体线程显示
            Invoke( new Action( ( ) =>
            {
                button_download.Enabled = true;
                button_download_cancel.Enabled = false;
                if (result.IsSuccess)
                {
                    // message: file download success
                    label15.Text = "文件下载成功!耗时:" + (DateTime.Now - downloadStartTime).TotalSeconds.ToString( "F1" ) + " 秒";
                }
                else
                {
                    // 失败原因多半来自网络异常,还有文件不存在,分类名称填写异常
                    // mostly failed by network exception, like offline, and file not exsist,
                    label15.Text = "文件下载失败:" + result.Message;
                    MessageBox.Show( "文件下载失败:" + result.ToMessageShowString( ) );
                }
            } ) );
        }  
        /// <summary>
        /// 用于更新文件下载进度的方法,该方法是线程安全的,主要作用是将下载文件的进度在进度条上显示
        /// </summary>
        /// <param name="receive">已经接收的字节数</param>
        /// <param name="totle">总字节数</param>
        private void DownloadReportProgress( long receive, long totle )
        {
            if (progressBar2.InvokeRequired)
            {
                progressBar2.Invoke( new Action<long, long>( DownloadReportProgress ), receive, totle );
                return;
            }

            // 此处代码是线程安全的
            // thread-safe code
            int value = (int)(receive * 100L / totle);
            progressBar2.Value = value;
            label9.Text = SoftBasic.GetSizeDescription( receive ) + "/" + SoftBasic.GetSizeDescription( totle );   // 已下载/总大小
        }

  

 

posted @ 2026-02-06 14:18  dathlin  阅读(129)  评论(0)    收藏  举报