Renci SSH.NET: Is it possible to create a folder containing a subfolder that does not exist

和自甴很熟 提交于 2019-12-05 23:16:35

There's no other way.

Just iterate directory levels, testing each level using SftpClient.GetAttributes and create the levels that does 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);
        }
    }
}

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);
}

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("/");
    }

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

A little modification on the accepted answer to use spans.

It's probably utterly pointless in this case, since the overhead of the sftp client is far greater than copying strings, but it can be useful in other similiar scenarios:

        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.") { }
            }
        }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!