Renci SSH.NET: Is it possible to create a folder containing a subfolder that does not exist
Solution 1
There's no other way.
Just iterate directory levels, testing each level using SftpClient.GetAttributes
and create the levels that do not exist.
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);
}
}
}
Solution 2
A little improvement on the code provided by Martin Prikryl
Don't use Exceptions as a flow control mechanism. The better alternative here is to check if the current path exists first.
if (client.Exists(current))
{
SftpFileAttributes attrs = client.GetAttributes(current);
if (!attrs.IsDirectory)
{
throw new Exception("not directory");
}
}
else
{
client.CreateDirectory(current);
}
instead of the try catch construct
try
{
SftpFileAttributes attrs = client.GetAttributes(current);
if (!attrs.IsDirectory)
{
throw new Exception("not directory");
}
}
catch (SftpPathNotFoundException)
{
client.CreateDirectory(current);
}
Solution 3
Hi I found my answer quite straight forwared. Since I found this old post, I thought others might also stumble upon it. The accepted answer is not that good, so here is my take. It does not use any counting gimmicks, so I think it's a little more easy to understand.
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("/");
}
Solution 4
FWIW, here's my rather simple take on it. The one requirement is that the server destination path is seperated by forward-slashes, as is the norm. I check for this before calling the function.
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
Erik
Updated on July 26, 2022Comments
-
Erik almost 2 years
I am currently using Renci SSH.NET to upload files and folders to a Unix Server using SFTP, and creating directories using
sftp.CreateDirectory("//server/test/test2");
works perfectly, as long as the folder "test" already exists. If it doesn't, the
CreateDirectory
method fails, and this happens everytime when you try to create directories containing multiple levels.Is there an elegant way to recursively generate all the directories in a string? I was assuming that the
CreateDirectory
method does that automatically. -
Martin Prikryl over 7 yearsAlso worth saying that your code is less efficient as it requires two round trips to the server for each directory level. Note how the
.Exists
is implemented. Internally it does exactly what my original code do. It calls.GetAttributes
and returnstrue
if it does not throw. And it if throws, it catches theSftpPathNotFoundException
and returnsfalse
. So you only seemingly avoided using exceptions for control flow. That's why I chose a variant with a single call and thetry
...catch
construct. If a latency to the server is big, you will tell a difference. +1 anyway :) -
Martin Prikryl over 7 years+ Do not base your answer on an exiting one. Your answer has has to stand on its own. So please include a complete code, instead of saying "use this instead of that in that code". Of course, acknowledging source of the code is expected.
-
Martin Prikryl over 4 yearsMy (accepted) answer is longer, because 1) it does not have the side effect of changing the working directory 2) it is more efficient, as it does not change working directory (you will tell the difference, if your connection has big latency). 3) Your answer will not report an error, if there's an existing file that matches the name of the directory you want to create.
-
Tom McDonough almost 4 yearsI get issues on my SFTP server on couchdrop, a forward slash is encoded to %2F