9

What I'm trying to do is to upload a website using FTP in C# (C Sharp). So I need to upload all files and folders within a folder, keeping its structure. I'm using this FTP class: http://www.codeproject.com/Tips/443588/Simple-Csharp-FTP-Class for the actual uploading.

I have come to the conclusion that I need to write a recursive method that goes through every sub-directory of the main directory and upload all files and folders in it. This should make an exact copy of my folder to the FTP. Problem is... I have no clue how to write a method like that. I have written recursive methods before but I'm new to the FTP part.

This is what I have so far:

private void recursiveDirectory(string directoryPath)
    {
        string[] filePaths = null;
        string[] subDirectories = null;

        filePaths = Directory.GetFiles(directoryPath, "*.*");
        subDirectories = Directory.GetDirectories(directoryPath);

        if (filePaths != null && subDirectories != null)
        {
            foreach (string directory in subDirectories)
            {
                ftpClient.createDirectory(directory);
            }
            foreach (string file in filePaths)
            {
                ftpClient.upload(Path.GetDirectoryName(directoryPath), file);
            }
        }
    }

But its far from done and I don't know how to continue. I'm sure more than me needs to know this! Thanks in advance :)

Ohh and... It would be nice if it reported its progress too :) (I'm using a progress bar)

EDIT: It might have been unclear... How do I upload a directory including all sub-directories and files with FTP?

hsson
  • 595
  • 1
  • 7
  • 16
  • Lets solve a simple problem first. Write a method that will loop through each Folder within the parent folder and create it on the website in question. Once you do that it should be easy enough to upload each file in each of those folders. You don't have enough done for us to help you. I can't believe you have the nerve to make feature requests..... – Security Hound Nov 09 '12 at 16:31
  • 1
    To create a progress bar you will need to get all the files which need to be uploaded. I would store the file paths in a List. Then loop through the file paths to upload them to the FTP server. After each upload then update the progress. A more accurate bar could be achieved by storing the size of the file with the file path. Then as each file is uploaded increment the progress by the size of the file. If you need I may add an example latter. – Trisped Nov 09 '12 at 18:42

4 Answers4

18

Problem Solved! :)

Alright so I managed to write the method myslef. If anyone need it feel free to copy:

private void recursiveDirectory(string dirPath, string uploadPath)
    {
        string[] files = Directory.GetFiles(dirPath, "*.*");
        string[] subDirs = Directory.GetDirectories(dirPath);

        foreach (string file in files)
        {
            ftpClient.upload(uploadPath + "/" + Path.GetFileName(file), file);
        }

        foreach (string subDir in subDirs)
        {
            ftpClient.createDirectory(uploadPath + "/" + Path.GetFileName(subDir));
            recursiveDirectory(subDir, uploadPath + "/" + Path.GetFileName(subDir));
        }
    }

It works very well :)

hsson
  • 595
  • 1
  • 7
  • 16
  • 1
    It would work if you would have mentioned that you used and external library to do that code, which include a lot of other code not made by you. – Liquid Core Sep 05 '13 at 09:30
  • 1
    He did in the question. But yea I'd like the redundancy too, rather than having to hunt for the link. – CyberFox Sep 11 '13 at 11:31
  • This ends up creating all the files and directories remotely, but all the files have a file size of 0B. ??? – mellis481 Sep 19 '14 at 14:57
  • Strange. I have no idea how that class works for anyone. I was able to fix their `upload()` method by changing the `FileMode` value to `Open`: `FileStream localFileStream = new FileStream(localFile, FileMode.Open);` – mellis481 Sep 19 '14 at 16:19
4

I wrote an FTP classe and also wrapped it in a WinForms user control. You can see my code in the article An FtpClient Class and WinForm Control.

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
1

I wrote a reusable class to upload entire directory to an ftp site on windows server,
the program also renames the old version of that folder (i use it to upload my windows service program to the server). maybe some need this:

class MyFtpClient
{
    protected string FtpUser { get; set; }
    protected string FtpPass { get; set; }
    protected string FtpServerUrl { get; set; }
    protected string DirPathToUpload { get; set; }
    protected string BaseDirectory { get; set; }

    public MyFtpClient(string ftpuser, string ftppass, string ftpserverurl, string dirpathtoupload)
    {
        this.FtpPass = ftppass;
        this.FtpUser = ftpuser;
        this.FtpServerUrl = ftpserverurl;
        this.DirPathToUpload = dirpathtoupload;
        var spllitedpath = dirpathtoupload.Split('\\').ToArray();
        // last index must be the "base" directory on the server
        this.BaseDirectory = spllitedpath[spllitedpath.Length - 1];
    }


    public void UploadDirectory()
    {
        // rename the old folder version (if exist)
        RenameDir(BaseDirectory);
        // create a parent folder on server
        CreateDir(BaseDirectory);
        // upload the files in the most external directory of the path
        UploadAllFolderFiles(DirPathToUpload, BaseDirectory);
        // loop trough all files in subdirectories



        foreach (string dirPath in Directory.GetDirectories(DirPathToUpload, "*",
        SearchOption.AllDirectories))
        {
            // create the folder
            CreateDir(dirPath.Substring(dirPath.IndexOf(BaseDirectory), dirPath.Length - dirPath.IndexOf(BaseDirectory)));

            Console.WriteLine(dirPath.Substring(dirPath.IndexOf(BaseDirectory), dirPath.Length - dirPath.IndexOf(BaseDirectory)));
            UploadAllFolderFiles(dirPath, dirPath.Substring(dirPath.IndexOf(BaseDirectory), dirPath.Length - dirPath.IndexOf(BaseDirectory))
        }
    }

    private void UploadAllFolderFiles(string localpath, string remotepath)
    {
        string[] files = Directory.GetFiles(localpath);
        // get only the filenames and concat to remote path
        foreach (string file in files)
        {
            // full remote path
            var fullremotepath = remotepath + "\\" + Path.GetFileName(file);
            // local path
            var fulllocalpath = Path.GetFullPath(file);
            // upload to server
            Upload(fulllocalpath, fullremotepath);
        }

    }

    public bool CreateDir(string dirname)
    {
        try
        {
            WebRequest request = WebRequest.Create("ftp://" + FtpServerUrl + "/" + dirname);
            request.Method = WebRequestMethods.Ftp.MakeDirectory;
            request.Proxy = new WebProxy();
            request.Credentials = new NetworkCredential(FtpUser, FtpPass);
            using (var resp = (FtpWebResponse)request.GetResponse())
            {
                if (resp.StatusCode == FtpStatusCode.PathnameCreated)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        catch
        {
            return false;
        }
    }

    public void Upload(string filepath, string targetpath)
    {

        using (WebClient client = new WebClient())
        {
            client.Credentials = new NetworkCredential(FtpUser, FtpPass);
            client.Proxy = null;
            var fixedpath = targetpath.Replace(@"\", "/");
            client.UploadFile("ftp://" + FtpServerUrl + "/" + fixedpath, WebRequestMethods.Ftp.UploadFile, filepath);
        }
    }

    public bool RenameDir(string dirname)
    {
        var path = "ftp://" + FtpServerUrl + "/" + dirname;
        string serverUri = path;

        try
        {
            FtpWebRequest request = (FtpWebRequest)WebRequest.Create(serverUri);
            request.Method = WebRequestMethods.Ftp.Rename;
            request.Proxy = null;
            request.Credentials = new NetworkCredential(FtpUser, FtpPass);
            // change the name of the old folder the old folder
            request.RenameTo = DateTime.Now.ToString("yyyyMMddHHmmss"); 
            FtpWebResponse response = (FtpWebResponse)request.GetResponse();

            using (var resp = (FtpWebResponse)request.GetResponse())
            {
                if (resp.StatusCode == FtpStatusCode.FileActionOK)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }
        catch
        {
            return false;
        }
    }
}

Create an instance of that class:

static void Main(string[] args)
{
    MyFtpClientftp = new MyFtpClient(ftpuser, ftppass, ftpServerUrl, @"C:\Users\xxxxxxxxxxx");
    ftp.UploadDirectory();
    Console.WriteLine("DONE");
    Console.ReadLine();
}
Jonathan Applebaum
  • 5,738
  • 4
  • 33
  • 52
  • Bravo!! This is the best solution I have found so far. It is just missing the destination folder to make it even better. – Max Vargas Sep 13 '18 at 21:52
0

Unless you're doing this for fun or self-improvement, use a commercial module. I can recommend one from Chilkat, but I'm sure there are others.

Note: I'm pretty sure this does answer the stated problem, What I'm trying to do is to upload a website using FTP in C# (C Sharp).

egrunin
  • 24,650
  • 8
  • 50
  • 93