私はRenci.SshNetライブラリを使用して、SFTPを使用してファイルとディレクトリのリストを再帰的に取得しています。SFTPサイトに接続できますが、C#でディレクトリとファイルのリストを再帰的に取得する方法がわかりません。有用な例は見つかりませんでした。
誰かがこれを試しましたか?もしそうなら、これらのファイルとフォルダを再帰的に取得する方法についてのサンプルコードを投稿できますか?
ありがとう、
プラヴ
ChangeDirectory
このライブラリには、との間の相互作用ListDirectory
が期待どおりに機能しないため、この再帰的なリストを扱いにくくするいくつかの癖があります。
以下は、/home ディレクトリ内のファイルを一覧表示するのではなく、/ (ルート) ディレクトリ内のファイルを一覧表示します。
sftp.ChangeDirectory("home");
sftp.ListDirectory("").Select (s => s.FullName);
以下は機能せず、SftpPathNotFoundException を返します。
sftp.ChangeDirectory("home");
sftp.ListDirectory("home").Select (s => s.FullName);
/home ディレクトリ内のファイルを一覧表示する正しい方法は次のとおりです。
sftp.ChangeDirectory("/");
sftp.ListDirectory("home").Select (s => s.FullName);
あなたが私に尋ねると、これはかなりクレイジーです。メソッドで既定のディレクトリを設定しても、このメソッドのパラメーターでフォルダーを指定しない限りChangeDirectory
、メソッドには影響しません。ListDirectory
これにはバグを書く必要があるようです。
したがって、再帰関数を記述するときは、デフォルト ディレクトリを一度設定してからListDirectory
、フォルダを反復処理するときに呼び出しでディレクトリを変更する必要があります。このリストは、列挙可能な SftpFiles を返します。これらは、個別にチェックできますIsDirectory == true
。.
リストにはおよび..
エントリ (ディレクトリ)も返されることに注意してください。無限ループを回避したい場合は、これらをスキップしてください。:-)
2018年2月23日編集
私は古い回答のいくつかを見直していましたが、上記の回答についてお詫びし、次の作業コードを提供したいと思います。ChangeDirectory
この例では を必要としないことに注意してFullname
くださいListDirectory
。
void Main()
{
using (var client = new Renci.SshNet.SftpClient("sftp.host.com", "user", "password"))
{
var files = new List<String>();
client.Connect();
ListDirectory(client, ".", ref files);
client.Disconnect();
files.Dump();
}
}
void ListDirectory(SftpClient client, String dirName, ref List<String> files)
{
foreach (var entry in client.ListDirectory(dirName))
{
if (entry.IsDirectory)
{
ListDirectory(client, entry.FullName, ref files);
}
else
{
files.Add(entry.FullName);
}
}
}
これを試して:
var filePaths = client.ListDirectory(client.WorkingDirectory);
再帰を使用してこれを達成しました。このようなクラス TransportResponse を作成しました
public class TransportResponse
{
public string directoryName { get; set; }
public string fileName { get; set; }
public DateTime fileTimeStamp { get; set; }
public MemoryStream fileStream { get; set; }
public List<TransportResponse> lstTransportResponse { get; set; }
}
TransportResponse クラスのリストを作成します。directoryName が null でない場合、そのディレクトリ内のファイルを MemoryStream として持つ同じクラスのリストが含まれます (これは、ユース ケースに応じて変更できます)。
List<TransportResponse> lstResponse = new List<TransportResponse>();
using (var client = new SftpClient(connectionInfo))
{
try
{
Console.WriteLine("Connecting to " + connectionInfo.Host + " ...");
client.Connect();
Console.WriteLine("Connected to " + connectionInfo.Host + " ...");
}
catch (Exception ex)
{
Console.WriteLine("Could not connect to "+ connectionInfo.Host +" server. Exception Details: " + ex.Message);
}
if (client.IsConnected)
{
var files = client.ListDirectory(transport.SourceFolder);
lstResponse = downloadFilesInDirectory(files, client);
client.Disconnect();
}
else
{
Console.WriteLine("Could not download files from "+ transport.TransportIdentifier +" because client was not connected.");
}
}
private static List<TransportResponse> downloadFilesInDirectory(IEnumerable<SftpFile> files, SftpClient client)
{
List<TransportResponse> lstResponse = new List<TransportResponse>();
foreach (var file in files)
{
if (!file.IsDirectory)
{
if (file.Name != "." && file.Name != "..")
{
if (!TransportDAL.checkFileExists(file.Name, file.LastWriteTime))
{
using (MemoryStream fs = new MemoryStream())
{
try
{
Console.WriteLine("Reading " + file.Name + "...");
client.DownloadFile(file.FullName, fs);
fs.Seek(0, SeekOrigin.Begin);
lstResponse.Add(new TransportResponse { fileName = file.Name, fileTimeStamp = file.LastWriteTime, fileStream = new MemoryStream(fs.GetBuffer()) });
}
catch(Exception ex)
{
Console.WriteLine("Error reading File. Exception Details: " + ex.Message);
}
}
}
else
{
Console.WriteLine("File was downloaded previously");
}
}
}
else
{
if (file.Name != "." && file.Name != "..")
{
lstResponse.Add(new TransportResponse { directoryName = file.Name,lstTransportResponse = downloadFilesInDirectory(client.ListDirectory(file.Name), client) });
}
}
}
return lstResponse;
}
お役に立てれば。ありがとう