基于.NET Framework 4.0的FTP文件传输类

1. 核心技术原理

这个FTP客户端基于.NET Framework 4.0的System.Net命名空间,主要使用了:

  • FtpWebRequest:用于创建FTP请求
  • FtpWebResponse:接收FTP服务器响应
  • NetworkCredential:处理身份验证

2. 关键类组件说明

FtpClient类结构
csharp 复制代码
- ftpServerIP: FTP服务器IP地址
- ftpUserID: 登录用户名
- ftpPassword: 登录密码
- ftpPort: FTP端口(默认21)

3. 核心功能详解

上传文件 (UploadFile)
复制代码
工作流程:
1. 构建FTP URI路径
2. 创建FtpWebRequest并设置为上传模式
3. 使用FileStream读取本地文件
4. 通过缓冲区分块传输数据
5. 完成后关闭所有流

关键设置:

  • UseBinary = true:使用二进制模式,确保文件完整性
  • KeepAlive = false:每次请求后关闭连接,避免超时
  • ContentLength:设置文件大小,让服务器知道传输量
  • 缓冲区2KB:平衡内存使用和传输效率
下载文件 (DownloadFile)
复制代码
工作流程:
1. 创建下载请求
2. 获取服务器响应流
3. 创建本地文件(自动创建目录)
4. 分块读取并写入本地文件
5. 关闭所有资源

4. Linux兼容性考虑

  • 路径分隔符 :Linux使用/,代码中远程路径使用正斜杠
  • 权限处理:确保FTP用户在Linux上有相应的读写权限
  • 编码问题:使用UTF-8编码处理文件名,支持中文
  • 二进制模式:避免Windows/Linux换行符差异

5. 错误处理机制

每个方法都包含完整的异常处理:

  • try-catch-finally结构确保资源释放
  • 返回布尔值表示操作成功/失败
  • 控制台输出错误信息便于调试

6. 性能优化要点

  1. 缓冲区大小:2KB适合大多数场景,可根据网络状况调整
  2. 超时设置:30秒超时避免长时间等待
  3. KeepAlive=false:避免连接池问题
  4. 资源管理:finally块确保流正确关闭

7. 安全性建议

  1. 加密传输:考虑使用FTPS(FTP over SSL)
  2. 凭据保护:不要硬编码密码,使用配置文件或加密存储
  3. 输入验证:验证文件路径防止路径遍历攻击
  4. 错误信息:生产环境避免暴露详细错误信息

8. 使用注意事项

Linux服务器配置
bash 复制代码
# 确保FTP服务运行
sudo service vsftpd status

# 配置文件权限
chmod 755 /ftp/directory
chown ftpuser:ftpgroup /ftp/directory
防火墙设置
  • 开放21端口(控制连接)
  • 配置被动模式端口范围

9. 扩展建议

  1. 异步操作:对于大文件,考虑使用异步方法
  2. 进度报告:添加传输进度回调
  3. 断点续传:实现REST命令支持
  4. 连接池:频繁操作时维护连接池
csharp 复制代码
using System;
using System.IO;
using System.Net;
using System.Text;

namespace FtpFileTransfer
{
    /// <summary>
    /// FTP文件传输类,用于向Linux设备上传下载文件
    /// </summary>
    public class FtpClient
    {
        private string ftpServerIP;
        private string ftpUserID;
        private string ftpPassword;
        private int ftpPort;
        
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="serverIP">FTP服务器IP地址</param>
        /// <param name="userID">用户名</param>
        /// <param name="password">密码</param>
        /// <param name="port">端口号(默认21)</param>
        public FtpClient(string serverIP, string userID, string password, int port = 21)
        {
            this.ftpServerIP = serverIP;
            this.ftpUserID = userID;
            this.ftpPassword = password;
            this.ftpPort = port;
        }
        
        /// <summary>
        /// 上传文件到FTP服务器
        /// </summary>
        /// <param name="localFilePath">本地文件完整路径</param>
        /// <param name="remoteFileName">远程文件名(包含路径)</param>
        /// <returns>上传是否成功</returns>
        public bool UploadFile(string localFilePath, string remoteFileName)
        {
            FileInfo fileInfo = new FileInfo(localFilePath);
            string uri = string.Format("ftp://{0}:{1}/{2}", ftpServerIP, ftpPort, remoteFileName);
            
            FtpWebRequest request = null;
            FileStream fs = null;
            Stream requestStream = null;
            
            try
            {
                // 创建FTP请求
                request = (FtpWebRequest)WebRequest.Create(new Uri(uri));
                request.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
                request.KeepAlive = false;
                request.Method = WebRequestMethods.Ftp.UploadFile;
                request.UseBinary = true;  // 二进制模式传输
                request.ContentLength = fileInfo.Length;
                request.Timeout = 30000;  // 30秒超时
                
                // 缓冲区大小设置为2KB
                int buffLength = 2048;
                byte[] buff = new byte[buffLength];
                int contentLen;
                
                // 打开本地文件流
                fs = fileInfo.OpenRead();
                
                // 获取FTP请求流
                requestStream = request.GetRequestStream();
                
                // 读取文件并写入FTP流
                contentLen = fs.Read(buff, 0, buffLength);
                while (contentLen != 0)
                {
                    requestStream.Write(buff, 0, contentLen);
                    contentLen = fs.Read(buff, 0, buffLength);
                }
                
                Console.WriteLine("文件 {0} 上传成功", fileInfo.Name);
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine("上传文件时发生错误: " + ex.Message);
                return false;
            }
            finally
            {
                // 关闭流
                if (requestStream != null)
                    requestStream.Close();
                if (fs != null)
                    fs.Close();
                if (request != null)
                    request.Abort();
            }
        }
        
        /// <summary>
        /// 从FTP服务器下载文件
        /// </summary>
        /// <param name="remoteFileName">远程文件名(包含路径)</param>
        /// <param name="localFilePath">本地保存路径</param>
        /// <returns>下载是否成功</returns>
        public bool DownloadFile(string remoteFileName, string localFilePath)
        {
            string uri = string.Format("ftp://{0}:{1}/{2}", ftpServerIP, ftpPort, remoteFileName);
            
            FtpWebRequest request = null;
            FtpWebResponse response = null;
            Stream responseStream = null;
            FileStream outputStream = null;
            
            try
            {
                // 创建FTP请求
                request = (FtpWebRequest)WebRequest.Create(new Uri(uri));
                request.Method = WebRequestMethods.Ftp.DownloadFile;
                request.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
                request.UseBinary = true;
                request.KeepAlive = false;
                request.Timeout = 30000;
                
                // 获取响应
                response = (FtpWebResponse)request.GetResponse();
                responseStream = response.GetResponseStream();
                
                // 创建本地文件
                string directoryPath = Path.GetDirectoryName(localFilePath);
                if (!Directory.Exists(directoryPath))
                {
                    Directory.CreateDirectory(directoryPath);
                }
                
                outputStream = new FileStream(localFilePath, FileMode.Create);
                
                // 缓冲区
                byte[] buffer = new byte[2048];
                int readCount = responseStream.Read(buffer, 0, buffer.Length);
                
                // 读取并写入文件
                while (readCount > 0)
                {
                    outputStream.Write(buffer, 0, readCount);
                    readCount = responseStream.Read(buffer, 0, buffer.Length);
                }
                
                Console.WriteLine("文件下载成功,保存到: {0}", localFilePath);
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine("下载文件时发生错误: " + ex.Message);
                return false;
            }
            finally
            {
                // 关闭流和响应
                if (outputStream != null)
                    outputStream.Close();
                if (responseStream != null)
                    responseStream.Close();
                if (response != null)
                    response.Close();
                if (request != null)
                    request.Abort();
            }
        }
        
        /// <summary>
        /// 获取FTP服务器上的文件列表
        /// </summary>
        /// <param name="remotePath">远程路径</param>
        /// <returns>文件列表</returns>
        public string[] GetFileList(string remotePath)
        {
            string uri = string.Format("ftp://{0}:{1}/{2}", ftpServerIP, ftpPort, remotePath);
            
            try
            {
                FtpWebRequest request = (FtpWebRequest)WebRequest.Create(new Uri(uri));
                request.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
                request.Method = WebRequestMethods.Ftp.ListDirectory;
                request.KeepAlive = false;
                
                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
                
                string line = reader.ReadLine();
                StringBuilder result = new StringBuilder();
                
                while (line != null)
                {
                    result.Append(line);
                    result.Append("\n");
                    line = reader.ReadLine();
                }
                
                reader.Close();
                response.Close();
                
                if (result.Length > 0)
                {
                    result.Remove(result.ToString().LastIndexOf('\n'), 1);
                    return result.ToString().Split('\n');
                }
                else
                {
                    return new string[] { };
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("获取文件列表时发生错误: " + ex.Message);
                return new string[] { };
            }
        }
        
        /// <summary>
        /// 删除FTP服务器上的文件
        /// </summary>
        /// <param name="remoteFileName">远程文件名</param>
        /// <returns>删除是否成功</returns>
        public bool DeleteFile(string remoteFileName)
        {
            string uri = string.Format("ftp://{0}:{1}/{2}", ftpServerIP, ftpPort, remoteFileName);
            
            try
            {
                FtpWebRequest request = (FtpWebRequest)WebRequest.Create(new Uri(uri));
                request.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
                request.Method = WebRequestMethods.Ftp.DeleteFile;
                request.KeepAlive = false;
                
                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                response.Close();
                
                Console.WriteLine("文件 {0} 删除成功", remoteFileName);
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine("删除文件时发生错误: " + ex.Message);
                return false;
            }
        }
        
        /// <summary>
        /// 创建FTP服务器上的目录
        /// </summary>
        /// <param name="directoryName">目录名</param>
        /// <returns>创建是否成功</returns>
        public bool CreateDirectory(string directoryName)
        {
            string uri = string.Format("ftp://{0}:{1}/{2}", ftpServerIP, ftpPort, directoryName);
            
            try
            {
                FtpWebRequest request = (FtpWebRequest)WebRequest.Create(new Uri(uri));
                request.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
                request.Method = WebRequestMethods.Ftp.MakeDirectory;
                request.KeepAlive = false;
                
                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                response.Close();
                
                Console.WriteLine("目录 {0} 创建成功", directoryName);
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine("创建目录时发生错误: " + ex.Message);
                return false;
            }
        }
        
        /// <summary>
        /// 检查文件是否存在
        /// </summary>
        /// <param name="remoteFileName">远程文件名</param>
        /// <returns>文件是否存在</returns>
        public bool FileExists(string remoteFileName)
        {
            string uri = string.Format("ftp://{0}:{1}/{2}", ftpServerIP, ftpPort, remoteFileName);
            
            try
            {
                FtpWebRequest request = (FtpWebRequest)WebRequest.Create(new Uri(uri));
                request.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
                request.Method = WebRequestMethods.Ftp.GetFileSize;
                request.KeepAlive = false;
                
                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                response.Close();
                return true;
            }
            catch
            {
                return false;
            }
        }
    }
    
    /// <summary>
    /// 使用示例
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            // 创建FTP客户端实例
            FtpClient ftpClient = new FtpClient(
                "192.168.1.100",  // Linux服务器IP
                "username",        // FTP用户名
                "password",        // FTP密码
                21                 // FTP端口(默认21)
            );
            
            // 上传文件示例
            bool uploadResult = ftpClient.UploadFile(
                @"C:\local\test.txt",           // 本地文件路径
                "/remote/path/test.txt"          // 远程文件路径
            );
            
            // 下载文件示例
            bool downloadResult = ftpClient.DownloadFile(
                "/remote/path/test.txt",        // 远程文件路径
                @"C:\download\test.txt"          // 本地保存路径
            );
            
            // 获取文件列表
            string[] files = ftpClient.GetFileList("/remote/path/");
            foreach (string file in files)
            {
                Console.WriteLine("文件: " + file);
            }
            
            // 检查文件是否存在
            bool exists = ftpClient.FileExists("/remote/path/test.txt");
            Console.WriteLine("文件存在: " + exists);
            
            // 创建目录
            ftpClient.CreateDirectory("/remote/newdir");
            
            // 删除文件
            ftpClient.DeleteFile("/remote/path/old.txt");
            
            Console.ReadLine();
        }
    }
}
相关推荐
一个帅气昵称啊5 小时前
.Net通过EFCore和仓储模式实现统一数据权限管控并且相关权限配置动态生成
.net·efcore·仓储模式
helloworddm7 小时前
CalculateGrainDirectoryPartition
服务器·c#·.net
步步为营DotNet8 小时前
深度剖析.NET中HttpClient的请求重试机制:可靠性提升与实践优化
开发语言·php·.net
ChaITSimpleLove8 小时前
使用 .net10 构建 AI 友好的 RSS 订阅机器人
人工智能·.net·mcp·ai bot·rss bot
专注VB编程开发20年8 小时前
vb.net宿主程序通过统一接口直接调用,命名空间要一致
服务器·前端·.net
ChaITSimpleLove1 天前
基于 .NET Garnet 1.0.91 实现高性能分布式锁(使用 Lua 脚本)
分布式·.net·lua
用户4488466710601 天前
.NET进阶——深入理解线程(2)Thread入门到精通
c#·.net
一个帅气昵称啊1 天前
.Net——AI智能体开发基于 Microsoft Agent Framework 实现第三方聊天历史存储
人工智能·microsoft·.net