📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

文字列「<source lang」を「<syntaxhighlight lang」に置換
 
(同じ利用者による、間の13版が非表示)
1行目: 1行目:
== 概要 ==
== 概要 ==
C# + SSH.NET + SFTPでファイル転送を行う方法を記載する。<br>
SFTP(Secure File Transfer Protocol)は、SSH(Secure Shell)プロトコルを使用してファイルを安全に転送するためのプロトコルの一種である。<br>
SSH.NETは、NuGetで入手可能の.NET Framework専用のSSHライブラリである。<br><br>
 
== 処理の流れ ==
1. 認証方法のインスタンスを生成する。<br>
  公開鍵認証またはパスワード認証を選択する。<br>
  公開鍵認証の場合は、ppk形式は指定できない。(例外が発生する)<br>
<br>
<br>
2. 接続情報のインスタンスを生成する。<br>
* セキュアな通信
  生成した認証方法のインスタンスをコンストラクタの引数で渡す。<br>
*: SFTPは、データ転送の際にSSHを使用するため、通信は暗号化され、セキュアである。
*: データの盗聴や改竄から保護されるため、非常に安全な転送方法とされている。
*: <br>
* ポート番号
*: SFTPは、SSHのポート番号を使用する。
*: しかし、SFTP専用のポートを使用することもできる。
*: <br>
* 利用方法
*: SFTPは、コマンドラインインターフェースやGUIツールを通じて使用できる。
*: 一般的なSFTPクライアントには、FileZilla、WinSCP、Cyberduck等が存在する。
*: <br>
* アクセス権の管理
*: SFTPは、SSHの認証メカニズムを使用するため、ユーザは、ユーザ名、パスワード、鍵を使用してサーバに接続する。
*: アクセス権はSSHの権限設定によって管理される。
*: <br>
* バッチ処理
*: SFTPはバッチ処理にも適している。
*: スクリプトを使用して、定期的なファイル転送や自動化されたタスクを実行できる。
<br>
<br>
3. sftpClientのインスタンスを生成する。<br>
C#において使用できるSSHライブラリとして、SSH.NET等がある。<br>
  接続情報のインスタンスをコンストラクタの引数に渡す。<br>
* SSH.NET
*: SSH.NETは、C#向けのOSSのSSHライブラリであり、SSH、SFTP、SCPの機能を提供している。
*: Renci.SshNetとは別のプロジェクトである。
*: <br>
*: SSH.NETのライセンスはMITである。
*: <br>
*: GitHub
*: https://github.com/sshnet/SSH.NET/
*: NuGet
*: https://www.nuget.org/packages/SSH.NET
<br>
<br>
4. 処理を記述する。(ダウンロード処理やアップロード処理)<br>
libSSH / libSSH2ライブラリを使用する場合は、C/C++で記述されているため、マーシャリングして使用する必要がある。<br>
ただし、これらの操作は煩雑であるため、SSH.NETライブラリを使用することを推奨する。<br>
<br><br>
 
== 処理の流れ ==
# 認証方法のインスタンスを生成する。
#: 公開鍵認証またはパスワード認証を選択する。
#: <u>公開鍵認証において、SSH.NETはppk形式の鍵ファイルをサポートしていない。 (例外が発生する)</u>
#: <u>そのため、あらかじめ、ppk形式をOpenSSH形式に変換する必要があることに注意する。</u>
#: <br>
# 接続情報のインスタンスを生成する。
#: 生成した認証方法のインスタンスをコンストラクタの引数で渡す。
#: <br>
# sftpClientのインスタンスを生成する。
#: 接続情報のインスタンスをコンストラクタの引数に渡す。
#: <br>
# 処理を記述する。
#: (ダウンロード処理やアップロード処理)
<br>
<br>
下記のサンプルコードでは、公開鍵認証を用いてユーザディレクトリのパスを取得するメソッドSystem.Environment.GetFolderPathを使用しているが、<br>
以下に示すサンプルコードでは、公開鍵認証を用いてユーザディレクトリのパスを取得するメソッドSystem.Environment.GetFolderPathを使用しているが、<br>
Linuxでも問題なくユーザディレクトリ配下のパスを取得できる。<br><br>
Linuxでも問題なくユーザディレクトリ配下のパスを取得できる。<br>
<br><br>


== サンプルコード ==
== 単一のファイルのダウンロード / アップロード ==
  <syntaxhighlight lang="c#">
  <syntaxhighlight lang="c#">
  using System;
  using System;
33行目: 71行目:
       string secretKeyPath = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".ssh",  
       string secretKeyPath = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".ssh",  
                                           "secret_key.pem");
                                           "secret_key.pem");
      var authMethod = new PrivateKeyAuthenticationMethod("username", new PrivateKeyFile(secretKeyPath, "finger_print"));
   
   
       // パスワード認証の場合(平文)
       // 公開鍵にパスフレーズが存在する場合
       //var authMethod = new PasswordAuthenticationMethod("username", "password");
      var authMethod = new PrivateKeyAuthenticationMethod("<リモートPCのユーザ名>",
                                                          new PrivateKeyFile(secretKeyPath, "<パスフレーズ>"));
      // 公開鍵にパスフレーズが無い場合
      //var authMethod = new PrivateKeyAuthenticationMethod("<リモートPCのユーザ名>",
      //                                                    new PrivateKeyFile(secretKeyPath, ""));
      // パスワード認証の場合
       //var authMethod = new PasswordAuthenticationMethod("<リモートPCのユーザ名>",
      //                                                  "<リモートPCのユーザ名のパスワード>");
   
   
       // 接続情報のインスタンス生成
       // 接続情報のインスタンス生成
       var connectionInfo = new ConnectionInfo("IPまたはホスト名", 22, "username", authMethod);
       var connectionInfo = new ConnectionInfo("<リモートPCのIPアドレス または ホスト名>",
                                              <ポート番号>,
                                              "<リモートPCのユーザ名>",
                                              authMethod);
   
   
       using (var client = new SftpClient(connectionInfo))
       using (var client = new SftpClient(connectionInfo))
77行目: 126行目:
     }
     }
  }
  }
  </source>
  </syntaxhighlight>
<br><br>
<br><br>


== 指定したディレクトリ配下のファイルを全てダウンロードする ==
== 複数のファイルのダウンロード ==
SSH.NETはディレクトリをダウンロードできないので、ディレクトリ内の全てのファイルのパスを取得して、個別にダウンロードする必要がある。<br>
SSH.NETはディレクトリ単位でダウンロードできない。<br>
下記のサンプルコードは、/home/usernameに存在するtestディレクトリ内のファイルを1つずつダウンロードするプログラムである。<br>
そのため、ディレクトリ内の全てのファイルをダウンロードする場青は、サーバ上にあるディレクトリのパスを指定して、個別にダウンロードする必要がある。<br>
<br>
以下の例では、リモートPC上にある/home/username/testディレクトリ内のファイルを全てダウンロードしている。<br>
<br>
<br>
  <syntaxhighlight lang="c#">
  <syntaxhighlight lang="c#">
  client.Connect();
  using System;
using System.IO;
using Renci.SshNet;
   
   
  var files = client.ListDirectory("/home/username/test").Where(x => x.Name != "." && x.Name != "..");
  class SftpDownloadMultipleFiles
foreach (var file in files)
  {
  {
     using (var fs = System.IO.File.OpenWrite(file.Name))
     static void Main(string[] args)
     {
     {
       client.DownloadFile(file.FullName, fs);
       // 公開鍵認証の場合
      // 例としてユーザディレクトリ配下の.sshディレクトリ内のsecret_key.pemを秘密鍵として使用
      string secretKeyPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".ssh", "secret_key.pem");
      var authMethod = new PrivateKeyAuthenticationMethod("username", new PrivateKeyFile(secretKeyPath, "finger_print"));
      // 公開鍵にパスフレーズが存在する場合
      var authMethod = new PrivateKeyAuthenticationMethod("<リモートPCのユーザ名>",
                                                          new PrivateKeyFile(secretKeyPath, "<パスフレーズ>"));
      // 公開鍵にパスフレーズが無い場合
      //var authMethod = new PrivateKeyAuthenticationMethod("<リモートPCのユーザ名>",
      //                                                    new PrivateKeyFile(secretKeyPath, ""));
      // パスワード認証の場合
      //var authMethod = new PasswordAuthenticationMethod("<リモートPCのユーザ名>",
      //                                                  "<リモートPCのユーザ名のパスワード>")
      // 接続情報のインスタンス生成
      var connectionInfo = new ConnectionInfo("<リモートPCのIPアドレス または ホスト名>",
                                              <ポート番号  例: 22>,
                                              "<リモートPCのユーザ名>",
                                              authMethod);
      using (var client = new SftpClient(connectionInfo))
      {
          // SSH接続を行う
          client.Connect();
          // リモートPCのユーザディレクトリに移動して、
          // 任意のディレクトリ (ここでは、/home/username/testディレクトリ) にある全てのファイルをダウンロードする
          var files = client.ListDirectory("/home/username/test").Where(x => x.Name != "." && x.Name != "..");
          foreach (var file in files)
          {
            // ファイル群を個別に書き込み専用で開く
            using (var fs = System.IO.File.OpenWrite(file.Name))
            {
                // ファイル群を個別にダウンロード
                client.DownloadFile(file.FullName, fs);
            }
          }
          // SSH接続を切断
          client.Disconnect();
      }
     }
     }
  }
  }
</syntaxhighlight>
<br><br>
== 複数のファイルのアップロード ==
以下の例では、アップロードするファイルのパスを配列で指定して、複数のファイルをリモートPC上にある/home/usernameディレクトリアップロードしている。<br>
ループ処理内において、1つずつファイルを読み込み、<code>UploadFile</code>メソッドを使用する。<br>
<br>
<syntaxhighlight lang="c#">
using System;
using System.IO;
using Renci.SshNet;
class SftpUploadMultipleFiles
{
    static void Main(string[] args)
    {
      // 公開鍵認証の場合
      // 例としてユーザディレクトリ配下の.sshディレクトリ内のsecret_key.pemを秘密鍵として使用
      string secretKeyPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".ssh", "secret_key.pem");
      var authMethod = new PrivateKeyAuthenticationMethod("username", new PrivateKeyFile(secretKeyPath, "finger_print"));
   
   
  client.Disconnect();
      // 公開鍵にパスフレーズが存在する場合
  </source>
      var authMethod = new PrivateKeyAuthenticationMethod("<リモートPCのユーザ名>",
                                                          new PrivateKeyFile(secretKeyPath, "<パスフレーズ>"));
      // 公開鍵にパスフレーズが無い場合
      //var authMethod = new PrivateKeyAuthenticationMethod("<リモートPCのユーザ名>",
      //                                                    new PrivateKeyFile(secretKeyPath, ""));
   
      // パスワード認証の場合
      //var authMethod = new PasswordAuthenticationMethod("<リモートPCのユーザ名>",
      //                                                  "<リモートPCのユーザ名のパスワード>")
      // 接続情報のインスタンス生成
      var connectionInfo = new ConnectionInfo("<リモートPCのIPアドレス または ホスト名>",
                                              <ポート番号  例: 22>,
                                              "<リモートPCのユーザ名>",
                                              authMethod);
      using (var client = new SftpClient(connectionInfo))
      {
          // SSH接続を行う
          client.Connect();
          // リモートPCのユーザディレクトリに移動
          client.ChangeDirectory("/home/username");
          // アップロードするファイルのパスを配列で指定
          string[] filePaths = { "/path/to/file1.txt", "/path/to/file2.jpg", "/path/to/file3.png" };
          foreach (string filePath in filePaths)
          {
            // ファイルを読み込み専用で開く
            using (var fs = File.OpenRead(filePath))
            {
                // ファイル名を取得
                string fileName = Path.GetFileName(filePath);
                // ファイルをアップロード(trueを指定すると上書き可能となる)
                client.UploadFile(fs, fileName, true);
            }
          }
          // SSH接続を切断
          client.Disconnect();
      }
    }
}
  </syntaxhighlight>
<br><br>
<br><br>


__FORCETOC__
__FORCETOC__
[[カテゴリ:C_Sharp]]
[[カテゴリ:C_Sharp]]