C# SFTP客户端实现文件传输功能
作者:Polevne
还在为SFTP和FTP的区别发愁,本文用最直白的方式讲清楚SSH、SFTP、FTP的端口和安全性差异,并手把手教你配置OpenSSH服务端、使用客户端进行文件管理,让你快速掌握安全文件传输的核心操作,需要的朋友可以参考下
一、SFTP信息
SSH:加密的远程登陆/命令通道协议,可以链接到另一台机器执行命令,也可以传输一些文件;
SFTP:跑在SSH上面的文件传输协议,端口为22;
FTP:1971年的明文传输协议,端口21,与SFTP没有关系;
二、服务端OpenSSH
1. systemctl enable --now ssh:开机自启 + 立即启动,启动的服务名为ssh.service
2. /etc/init.d/sshd start:运行sshd脚本,start为参数,还有stop啥的
3. ssh-keygen -A:生成密钥ssh_host_*_key,在服务端与客户端进行连接时,客户端发给服务端由它生成的公钥,服务端会留存这个公钥以识别OpenSSH
4. /etc/ssh/sshd_config为SSH的配置文件,里面有端口、登陆账号(即Linux账号)、密钥等;
三、客户端
1. 加载远程文件\目录列表
SftpClient client = new SftpClient(ip, port, userName, password); // 除了port为int外,其他参数都是string,用户名和密码是Linux允许访问OpenSSH账号名和密码,sshd_config AllowUser那里做配置的
client.Connect();
List<TransFileInfo> entries = client.ListDirectory(path) // path服务端的路径
.Where(t => t.Name != "." && t.Name != ".." && !t.Name.StartsWith('.')) // 剔除"."当前目录、".."上级目录、"."开头的配置文件
.OrderByDescending(t => t.IsDirectory)
.ThenBy(t => t.Name, StringComparer.OrdinalIgnoreCase)
.Select(t => mew TransFileInfo()
{
Name = t.Name,
Size = t.IsDirectory ? 0 : t.Length,
Time = t.LastWriteTime.ToString("yyyy-MM-dd HH:mm"),
IsDirectory = t.IsDirectory,
FullPath = t.Name
});2. 删除远程文件\目录
SftpClient client = new SftpClient(ip, port, userName, password);
client.Connect(); // SftpClient的创建和连接的成本很低,可以在每次执行时都创建并连接
SftpFileAttributes attrs = client.GetAttributes(deleteFilePath);
if (attrs.IsDirectory)
// 写个递归删除所有文件夹中的文件就行
else
client.DeleteFile(deleteFilePath);3. 重命名
client.RenameFile(oldFilePath, newPath);
4. 创建文件夹
client.CreateDirectory(dirPath);
5. 下载
long totalLength = client.GetAttributes(remotePath).Size; // 获取一下远程文件的大小
string tempPath = localPath + ".tmp"; // 先将远程文件保存至临时文件,结束后再删除掉.tmp后缀
long offset = 0;
if (File.Exits(tempPath))
{
offset = (new FileInfo(tempPath)).Length; // 因为提供的断点续传功能,所以临时文件的长度作为偏置,续传时就从这里开始
if (offset >= totalLength)
offset = totalLength; // 偏置为totalLength就算是下载完毕了
}
using StfpFileStream remoteStream = client.OpenRead(remotePath);
remoteStream.Seek(offset, SeekOrigin.Begin); // SeekOrigin.Begin从文件开头开始偏移
using FileStream localStream = new FileStream(tempPath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, 256 * 1024); // 每次只读取256kb
localStream.Seek(offset, SeekOrigin.Begin);
byte[] buffer = new byte[256 * 1024];
while(true)
{
if(!await Check())
continue;
int read = await remoteStream.ReadAsync(buffer.AsMemory(0, buffer.Length)); // Memory类似(指针 + 长度),由GC回收
if (read == 0)
break;
await localStream.WriteAsync(buffer.AsMemory(0, read));
}
// 回收流资源 + 复制临时文件
localStream.Dispose();
if (File.Exits(localPath))
File.Delete(localPath);
File.Move(tempPath, localPath);
async void Check()
{
TaskCompletionSource<bool>? tcs;
lock(_lock)
{
if (isPaused)
return false; // 这里省略了,isPaused为true时,while(true)那边不继续
tcs = _pauseTcs;
}
if (tcs != null)
await tcs.Task.ConfigureAwait(false); // 在这里等
}
void Resume()
{
TaskCompletionSource<bool>? tcs;
lock(_lock)
{
if (!isPaused)
return;
isPaused = false;
tcs = _pauseTcs;
_pauseTcs = null;
}
tcs?.TrySetResult(true);
}
void Cancel()
{
TaskCompletionSource<bool>? tcs;
lock(_lock)
{
if (isPaused)
return;
isPaused = true;
_pauseTcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationAsynchronously);
}
tcs?.TrySetResult(false);
}到此这篇关于C# SFTP客户端实现文件传输功能的文章就介绍到这了,更多相关C# SFTP客户端文件传输内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
