Renci SSH.NET: 是否可以创建一个包含不存在的子文件夹的文件夹
Renci SSH.NET: Is it possible to create a folder containing a subfolder that does not exist
我目前正在使用 Renci SSH.NET 通过 SFTP 将文件和文件夹上传到 Unix 服务器,并使用
创建目录
sftp.CreateDirectory("//server/test/test2");
完美运行,只要文件夹 "test" 已经存在。否则,CreateDirectory
方法将失败,每次您尝试创建包含多个级别的目录时都会发生这种情况。
有没有一种优雅的方法可以递归生成一个字符串中的所有目录?我假设 CreateDirectory
方法会自动执行此操作。
没有别的办法。
只需迭代目录级别,使用 SftpClient.GetAttributes
测试每个级别并创建不存在的级别。
static public void CreateDirectoryRecursively(this SftpClient client, string path)
{
string current = "";
if (path[0] == '/')
{
path = path.Substring(1);
}
while (!string.IsNullOrEmpty(path))
{
int p = path.IndexOf('/');
current += '/';
if (p >= 0)
{
current += path.Substring(0, p);
path = path.Substring(p + 1);
}
else
{
current += path;
path = "";
}
try
{
SftpFileAttributes attrs = client.GetAttributes(current);
if (!attrs.IsDirectory)
{
throw new Exception("not directory");
}
}
catch (SftpPathNotFoundException)
{
client.CreateDirectory(current);
}
}
}
对 Martin Prikryl 提供的代码稍作改进
不要使用异常作为流程控制机制。这里更好的选择是先检查当前路径是否存在。
if (client.Exists(current))
{
SftpFileAttributes attrs = client.GetAttributes(current);
if (!attrs.IsDirectory)
{
throw new Exception("not directory");
}
}
else
{
client.CreateDirectory(current);
}
而不是 try catch 构造
try
{
SftpFileAttributes attrs = client.GetAttributes(current);
if (!attrs.IsDirectory)
{
throw new Exception("not directory");
}
}
catch (SftpPathNotFoundException)
{
client.CreateDirectory(current);
}
FWIW,这是我对它的相当简单的看法。一个要求是服务器目标路径由 forward-slashes 分隔,这是一种规范。我在调用函数之前检查了这一点。
private void CreateServerDirectoryIfItDoesntExist(string serverDestinationPath, SftpClient sftpClient)
{
if (serverDestinationPath[0] == '/')
serverDestinationPath = serverDestinationPath.Substring(1);
string[] directories = serverDestinationPath.Split('/');
for (int i = 0; i < directories.Length; i++)
{
string dirName = string.Join("/", directories, 0, i + 1);
if (!sftpClient.Exists(dirName))
sftpClient.CreateDirectory(dirName);
}
}
HTH
对已接受的答案稍作修改以使用 span。
在这种情况下它可能完全没有意义,因为 sftp 客户端的开销远大于复制字符串,但它在其他类似场景中可能很有用:
public static void EnsureDirectory(this SftpClient client, string path)
{
if (path.Length is 0)
return;
var curIndex = 0;
var todo = path.AsSpan();
if (todo[0] == '/' || todo[0] == '\')
{
todo = todo.Slice(1);
curIndex++;
}
while (todo.Length > 0)
{
var endOfNextIndex = todo.IndexOf('/');
if (endOfNextIndex < 0)
endOfNextIndex = todo.IndexOf('\');
string current;
if (endOfNextIndex >= 0)
{
curIndex += endOfNextIndex + 1;
current = path.Substring(0, curIndex);
todo = path.AsSpan().Slice(curIndex);
}
else
{
current = path;
todo = ReadOnlySpan<char>.Empty;
}
try
{
client.CreateDirectory(current);
}
catch (SshException ex) when (ex.Message == "Already exists.") { }
}
}
您好,我发现我的回答很直接。自从我发现这个旧的 post,我想其他人也可能偶然发现它。接受的答案不是那么好,所以这是我的看法。它没有使用任何计数技巧,所以我认为它更容易理解。
public void CreateAllDirectories(SftpClient client, string path)
{
// Consistent forward slashes
path = path.Replace(@"\", "/");
foreach (string dir in path.Split('/'))
{
// Ignoring leading/ending/multiple slashes
if (!string.IsNullOrWhiteSpace(dir))
{
if(!client.Exists(dir))
{
client.CreateDirectory(dir);
}
client.ChangeDirectory(dir);
}
}
// Going back to default directory
client.ChangeDirectory("/");
}
我目前正在使用 Renci SSH.NET 通过 SFTP 将文件和文件夹上传到 Unix 服务器,并使用
创建目录sftp.CreateDirectory("//server/test/test2");
完美运行,只要文件夹 "test" 已经存在。否则,CreateDirectory
方法将失败,每次您尝试创建包含多个级别的目录时都会发生这种情况。
有没有一种优雅的方法可以递归生成一个字符串中的所有目录?我假设 CreateDirectory
方法会自动执行此操作。
没有别的办法。
只需迭代目录级别,使用 SftpClient.GetAttributes
测试每个级别并创建不存在的级别。
static public void CreateDirectoryRecursively(this SftpClient client, string path)
{
string current = "";
if (path[0] == '/')
{
path = path.Substring(1);
}
while (!string.IsNullOrEmpty(path))
{
int p = path.IndexOf('/');
current += '/';
if (p >= 0)
{
current += path.Substring(0, p);
path = path.Substring(p + 1);
}
else
{
current += path;
path = "";
}
try
{
SftpFileAttributes attrs = client.GetAttributes(current);
if (!attrs.IsDirectory)
{
throw new Exception("not directory");
}
}
catch (SftpPathNotFoundException)
{
client.CreateDirectory(current);
}
}
}
对 Martin Prikryl 提供的代码稍作改进
不要使用异常作为流程控制机制。这里更好的选择是先检查当前路径是否存在。
if (client.Exists(current))
{
SftpFileAttributes attrs = client.GetAttributes(current);
if (!attrs.IsDirectory)
{
throw new Exception("not directory");
}
}
else
{
client.CreateDirectory(current);
}
而不是 try catch 构造
try
{
SftpFileAttributes attrs = client.GetAttributes(current);
if (!attrs.IsDirectory)
{
throw new Exception("not directory");
}
}
catch (SftpPathNotFoundException)
{
client.CreateDirectory(current);
}
FWIW,这是我对它的相当简单的看法。一个要求是服务器目标路径由 forward-slashes 分隔,这是一种规范。我在调用函数之前检查了这一点。
private void CreateServerDirectoryIfItDoesntExist(string serverDestinationPath, SftpClient sftpClient)
{
if (serverDestinationPath[0] == '/')
serverDestinationPath = serverDestinationPath.Substring(1);
string[] directories = serverDestinationPath.Split('/');
for (int i = 0; i < directories.Length; i++)
{
string dirName = string.Join("/", directories, 0, i + 1);
if (!sftpClient.Exists(dirName))
sftpClient.CreateDirectory(dirName);
}
}
HTH
对已接受的答案稍作修改以使用 span。
在这种情况下它可能完全没有意义,因为 sftp 客户端的开销远大于复制字符串,但它在其他类似场景中可能很有用:
public static void EnsureDirectory(this SftpClient client, string path)
{
if (path.Length is 0)
return;
var curIndex = 0;
var todo = path.AsSpan();
if (todo[0] == '/' || todo[0] == '\')
{
todo = todo.Slice(1);
curIndex++;
}
while (todo.Length > 0)
{
var endOfNextIndex = todo.IndexOf('/');
if (endOfNextIndex < 0)
endOfNextIndex = todo.IndexOf('\');
string current;
if (endOfNextIndex >= 0)
{
curIndex += endOfNextIndex + 1;
current = path.Substring(0, curIndex);
todo = path.AsSpan().Slice(curIndex);
}
else
{
current = path;
todo = ReadOnlySpan<char>.Empty;
}
try
{
client.CreateDirectory(current);
}
catch (SshException ex) when (ex.Message == "Already exists.") { }
}
}
您好,我发现我的回答很直接。自从我发现这个旧的 post,我想其他人也可能偶然发现它。接受的答案不是那么好,所以这是我的看法。它没有使用任何计数技巧,所以我认为它更容易理解。
public void CreateAllDirectories(SftpClient client, string path)
{
// Consistent forward slashes
path = path.Replace(@"\", "/");
foreach (string dir in path.Split('/'))
{
// Ignoring leading/ending/multiple slashes
if (!string.IsNullOrWhiteSpace(dir))
{
if(!client.Exists(dir))
{
client.CreateDirectory(dir);
}
client.ChangeDirectory(dir);
}
}
// Going back to default directory
client.ChangeDirectory("/");
}