要約
C# SSH.NET の使用例です。
sshでsftpサーバに接続してファイルリストを取得します。
GitHubにサンプルコードを置いてあります。(https://github.com/unknown-ds/csharp_sftp)
環境
Windows 10
Visual Studio Express 2017 for Windows Desktop
Docker Desktop Community ver.2.0.0.3(31259)
参考
テスト用に以下のdocker-composeファイルを使わせて頂きました。ありがとうございます。
テスト用途のSFTP/FTPS/FTPサーバーを単独で起動するdocker-compose.ymlの例
実装
フォルダ構成
プロジェクトフォルダ以下にsftpサーバ用docker
フォルダを作っています。この下にアクセステスト用フォルダremote
と鍵が入っているフォルダssh
があります。
└─[projectroot]
├─[docker]
│ ├─[remote]
│ │ └─test.txt // テスト用テキストファイル
│ └─[ssh]
│ └─id_rsa // 秘密鍵
└─docker-compose.yml
ライブラリ
NugetでSSH.NETをインストールします。
テストクラス説明
コンストラクタで接続情報を用意し、Execute()
でテストをしています。
基本的な流れとしては
- Renci.SshNet.ConnectionInfoクラスを生成し、接続情報を用意する。
- Renci.SshNet.SftpClientのインスタンスを生成して接続/切断を行う。
- ファイルリストを取得する場合はListDirectoryで取得して処理。
- ファイルのアップロード/ダウンロードはUploadFile/DownloadFileメソッドにストリームを渡して処理する。
となります。
// SFTP接続クラス
public class CSftp
{
// 接続情報
public ConnectionInfo ConnNfo { private set; get; }
// 接続ホスト名
public string HostName { private set; get; }
// ポート
public Int32 Port { private set; get; }
// ユーザー名
public string UserName { private set; get; }
// パスワード
public string Password { private set; get; }
// コンストラクタ
public CSftp()
{
HostName = "localhost"; // 接続先ホスト名
Port = 10221; // ポート
UserName = "sftp-with-rsa-key"; // ユーザー名
Password = "1001"; // パスワード
string KeyFile = @"..\..\docker\ssh\id_rsa"; // 秘密鍵
string PassPhrase = ""; // パスフレーズ
// パスワード認証
var _PassAuth = new PasswordAuthenticationMethod(UserName, Password);
// 秘密鍵認証
var _PrivateKey = new PrivateKeyAuthenticationMethod(UserName, new PrivateKeyFile[]{
new PrivateKeyFile(KeyFile, PassPhrase)
});
// 接続情報の生成
ConnNfo = new ConnectionInfo(HostName, Port, UserName,
new AuthenticationMethod[]{
_PassAuth, // パスワード認証
_PrivateKey, // 秘密鍵認証
}
);
}
// 実行
public void Execute()
{
using (var sftp = new SftpClient(ConnNfo))
{
// 接続
sftp.Connect();
// 確認
if (sftp.IsConnected)
{
// 接続に成功
Console.WriteLine("Connection success!!\n");
}
else
{
// 接続に失敗
Console.WriteLine("Connection failed!!\n");
return;
}
// ファイルリスト表示
printFiles(sftp, "/remote");
// ファイル内容表示
printTxtFile(sftp, "/remote/test.txt");
// ファイルアップロード
uploadFile(sftp, "/remote", "../../Program.cs");
// 切断
sftp.Disconnect();
}
}
// ファイル表示
private void printFiles(
SftpClient _sftp, // sftpクライアント
string _Path // パス
)
{
// 指定パスを調べる
foreach (var file in _sftp.ListDirectory(_Path))
{
if (file.Name.StartsWith(".")) continue;
if (file.IsDirectory)
{
// ディレクトリなら再帰して調べる
printFiles(_sftp, file.FullName);
}
else
{
// 表示
Console.WriteLine($"{file.FullName}\t\t{file.LastAccessTime}\t{file.LastWriteTime}");
}
}
}
// 指定テキストファイルの表示
private void printTxtFile(
SftpClient _sftp, // sftpクライアント
string _FilePath // ファイルパス
)
{
var _CurDir = Path.GetDirectoryName(_FilePath).Substring(1);
var _FileName = Path.GetFileName(_FilePath);
// カレントディレクトリ変更
_sftp.ChangeDirectory(_CurDir);
foreach (var file in _sftp.ListDirectory("./"))
{
if (file.IsDirectory) continue;
if (file.Name != _FileName) continue;
// 読み込み
Int64 _Size = file.Length;
var _Buf = new byte[_Size];
using (var _St = new MemoryStream(_Buf, 0, (int)_Size))
{
_sftp.DownloadFile(file.FullName, _St);
}
// SJIS変換
string _str = Encoding.GetEncoding(932).GetString(_Buf);
// 内容表示
Console.WriteLine();
Console.WriteLine($"------------------{file.Name}");
Console.WriteLine($"{_str}");
Console.WriteLine("------------------");
}
}
// ファイルのアップロード
private void uploadFile(
SftpClient _sftp, // sftpクライアント
string _UploadPath, // アップロードパス
string _UploadFile // アップロードファイル名
)
{
// カレントディレクトリ変更
_sftp.ChangeDirectory(_UploadPath);
// アップロード先パス
var _RemotePath = _UploadPath + "/" + Path.GetFileName(_UploadFile);
using (var _uploadStream = File.OpenRead(_UploadFile))
{
_sftp.UploadFile(_uploadStream, _RemotePath, true);
}
}
}
注意点
日本語ファイル名を扱う際は、ConnectionInfoクラスのEncodingプロパティにエンコード情報を設定する。
実行例
docker-compose up -d
でsftpサーバを立ち上げます。
テストコードを実行し接続に成功すると以下のような出力になります。
ファイルリストの表示とtest.txt
の内容表示、Program.csのアップロードが行われます。
Connection success!!
/remote/test.txt 2019/04/16 11:17:52 2019/04/16 15:29:18
/remote/Program.cs 2019/04/16 16:40:02 2019/04/16 16:40:02
------------------test.txt
テスト用のテキストです。
------------------
SSH接続してコマンドで行う
シェルコマンドでやりとりする場合は、SshClientクラスインスタンスを生成してやり取りをすることができます。
using (var sshclient = new SshClient(ConnNfo))
{
sshclient.Connect();
using (var cmd = sshclient.CreateCommand("ls -lah"))
{
Console.WriteLine(cmd.Execute());
Console.WriteLine($"ExitStatus:{cmd.ExitStatus}");
}
sshclient.Disconnect();
}
シェル実行できない場合は(サーバ側で制限されている場合は)
This service allows sftp connections only.
という風にレスポンスが返ってきます。(ExistStatus は 1 です。)