使用FTP上传整个目录的C#代码

9
我想要做的是使用C#上传网站,需要使用FTP。因此,我需要上传文件夹中的所有文件和文件夹,并保持其结构。我正在使用这个FTP类:http://www.codeproject.com/Tips/443588/Simple-Csharp-FTP-Class进行实际上传。
我得出结论,我需要编写一个递归方法,遍历主目录下的每个子目录,并上传其中的所有文件和文件夹。这应该能够完全复制我的文件夹到FTP上。问题是...我不知道如何编写这样的方法。我之前写过递归方法,但对FTP部分不熟悉。
这是我目前所拥有的:
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);
            }
        }
    }

但它还远未完成,我不知道该如何继续。我相信不仅我需要知道这个!提前感谢 :)

哦,而且……如果它能报告进度就更好了 :) (我正在使用进度条)

编辑: 可能不太清楚……我如何使用FTP上传包括所有子目录和文件的目录?


让我们先解决一个简单的问题。编写一个方法,循环遍历父文件夹中的每个文件夹,并在相关网站上创建它。一旦完成这一步骤,上传每个文件夹中的每个文件就变得非常容易了。你还没有做足够的工作让我们帮助你。我无法相信你有胆量提出功能请求... - Security Hound
1
要创建一个进度条,您需要获取所有需要上传的文件。我会将文件路径存储在列表中。然后循环遍历文件路径以将它们上传到FTP服务器。每次上传后更新进度。通过将文件大小与文件路径一起存储,可以实现更准确的进度条。然后,每上传一个文件,就按文件大小增加进度。如果需要,我可以稍后添加一个示例。 - Trisped
4个回答

18

问题已解决! :)

好的,所以我设法自己编写了这个方法。 如果有人需要它,请随意复制:

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

它运行得非常好 :)


1
如果你提到了你使用了一个外部库来编写代码,其中包含了许多不是由你编写的其他代码,那么这个方法就可以工作。 - Liquid Core
1
他在问题中提到了。但是是的,我也喜欢冗余,而不是必须寻找链接。 - CyberFox
这最终会在远程创建所有文件和目录,但所有文件的文件大小都为0B。 - mellis481
奇怪。我不知道那个类如何对其他人起作用。我通过将“FileMode”值更改为“Open”来修复了他们的“upload()”方法:FileStream localFileStream = new FileStream(localFile, FileMode.Open); - mellis481

4

1
我编写了一个可重复使用的类,用于将整个目录上传到 Windows 服务器上的 FTP 网站,该程序还会重命名该文件夹的旧版本(我将其用于将我的 Windows 服务程序上传到服务器)。也许有些人需要这个:
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;
        }
    }
}

创建该类的一个实例:
static void Main(string[] args)
{
    MyFtpClientftp = new MyFtpClient(ftpuser, ftppass, ftpServerUrl, @"C:\Users\xxxxxxxxxxx");
    ftp.UploadDirectory();
    Console.WriteLine("DONE");
    Console.ReadLine();
}

太棒了!!这是我迄今为止找到的最佳解决方案。只是缺少目标文件夹,这样就更好了。 - Max Vargas

0

除非你是为了乐趣或自我提升而这样做,否则请使用商业模块。我可以推荐一个来自Chilkat的模块,但我相信还有其他选择。

注意:我很确定这个回答解决了所述问题:我正在尝试使用C#(C Sharp)中的FTP上传网站。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接