0%

[DotnetCore]SFTP-下載上傳

前情提要

筆者上篇介紹完FTP下載上傳後,另一個挑戰來了,有些系統指定使用SFTP協定來做交換(上傳、下載),剛好FluentFTP尚未支援SFTP協定,因此要轉戰其他套件了,筆者找到一套名為SSH.NET,這篇以主要介紹透過該套件實作SFTP協定的下載及上傳作業。IFtpService則延續使用上篇的定義,這邊多了一組SFtpService的實作來完成任務。

內容

安裝套件

1
dotnet add package SSH.NET

撰寫Service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
using Renci.SshNet;

public class SFtpService : IFtpService
{
private readonly IFilePathService _filePathService;
public SFtpService(IFilePathService filePathService)
{
_filePathService = filePathService;
}
public void DownloadData(FTPConfigBaseModel downloadFtpInfo, List<string> fileList)
{
var localDir = _filePathService.GetDirectoryPath(downloadFtpInfo.LocalPath);
var remoteDir = downloadFtpInfo.RemotePath;

var password = Encoding.UTF8.GetString(Convert.FromBase64String(downloadFtpInfo.Password));
var securePwd = PasswordExtension.SecureStringToString(
PasswordExtension.GetPasswordSecurity(password));
using (var client = new SftpClient(downloadFtpInfo.Server, downloadFtpInfo.Account, securePwd))
{
try
{
client.Connect();
foreach (var item in fileList)
{
var localPath = Path.Combine(localDir, item);
var remotePath = Path.Combine(remoteDir, item);
using(var s = File.Create(localPath))
client.DownloadFile(remotePath, s);
}
}
catch (Exception exception)
{
throw exception;
}
finally
{
client.Disconnect();
}
}
}

public void UploadData(FTPConfigBaseModel uploadFtpInfo, List<FileUploadResponseModel> fileUploadResponseModels)
{
// Step0: Data Initial
var localDir = _filePathService.GetDirectoryPath(uploadFtpInfo.LocalPath);
var remoteDir = uploadFtpInfo.RemotePath;
// Step1: Data Arrangement
var fileGroupList = fileUploadResponseModels.GroupBy(x => x.FileName).ToList();
var fileList = new List<string>();
foreach (var item in fileGroupList)
{
var fileContent = item.Select(x => x.DataStr)
.Aggregate((x, y) => $"{x}\r\n{y}");
File.WriteAllText(Path.Combine(localDir, item.Key)
, fileContent, Encoding.GetEncoding(item.FirstOrDefault()?.Encoding));
fileList.Add(item.Key);
}
// Step2: Upload Data
var password = Encoding.UTF8.GetString(Convert.FromBase64String(uploadFtpInfo.Password));
var securePwd = PasswordExtension.SecureStringToString(
PasswordExtension.GetPasswordSecurity(password));
using (var client = new SftpClient(uploadFtpInfo.Server, uploadFtpInfo.Account, securePwd))
{
try
{
client.Connect();
foreach (var item in fileList)
{
var localPath = Path.Combine(localDir, item);
var remotePath = Path.Combine(remoteDir, item);
using(var stream = new FileStream(localPath, FileMode.Open))
client.UploadFile(stream, remotePath, true);
}
}
catch (Exception exception)
{
throw exception;
}
finally
{
client.Disconnect();
}
}
}

public bool IsExist(FTPConfigBaseModel uploadFtpInfo, string filename)
{
var password = Encoding.UTF8.GetString(Convert.FromBase64String(uploadFtpInfo.Password));
var securePwd = PasswordExtension.SecureStringToString(
PasswordExtension.GetPasswordSecurity(password));
using (var client = new SftpClient(uploadFtpInfo.Server, uploadFtpInfo.Account, securePwd))
{
try
{
client.Connect();
var remotePath = Path.Combine(uploadFtpInfo.RemotePath, filename);
return client.Exists(remotePath);
}
catch (Exception exception)
{
throw exception;
}
finally
{
client.Disconnect();
}
}
}
}

Client端使用與Ftp那篇差不多,參考[DotnetCore]FTP-下載上傳即可。

結論

透過此篇介紹,簡單實現SFTP協定的存取,留個伏筆,因為FtpService與SFtpService皆實作IFtpService,若同一個專案皆有兩種需求則不能只是單注入IFtpService,這樣無法知道存取到的是哪個實作,因此需要做一些特別處理以辨別要使用哪個實作服務,下篇就來揭曉吧。