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. 性能优化要点
- 缓冲区大小:2KB适合大多数场景,可根据网络状况调整
- 超时设置:30秒超时避免长时间等待
- KeepAlive=false:避免连接池问题
- 资源管理:finally块确保流正确关闭
7. 安全性建议
- 加密传输:考虑使用FTPS(FTP over SSL)
- 凭据保护:不要硬编码密码,使用配置文件或加密存储
- 输入验证:验证文件路径防止路径遍历攻击
- 错误信息:生产环境避免暴露详细错误信息
8. 使用注意事项
Linux服务器配置
bash
# 确保FTP服务运行
sudo service vsftpd status
# 配置文件权限
chmod 755 /ftp/directory
chown ftpuser:ftpgroup /ftp/directory
防火墙设置
- 开放21端口(控制连接)
- 配置被动模式端口范围
9. 扩展建议
- 异步操作:对于大文件,考虑使用异步方法
- 进度报告:添加传输进度回调
- 断点续传:实现REST命令支持
- 连接池:频繁操作时维护连接池
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();
}
}
}