Ftp文件下载

Ftp 递归下载指定目录下所有文件

构建两个基础类型(为了保留目录下所有文件和目录,方便递归)

namespace LoadProject
{
    enum PathType {
        Unkown = -1,
        File = 0,
        Dir = 1     
    }
    struct FileStruct
    {
        public PathType FileType { set; get; }
        public string FilePath { get; set; }
        public string FileName { get; set; }
    }
}

基础类(FtpHelper)提供Ftp基本的操作

namespace LoadProject
{
    class FtpHelper
    {
        /// 
        /// 下载目录下所有的文件
        /// 
        /// ftp目录地址
        /// 目录名称
        /// 下载至本地目录地址对象
        /// 是否有用户名
        /// 用户名
        /// 密码
        public static void DownFtpDir(string ftpPath, string dirName, DirectoryInfo parentDir, bool withUser = false, string userName = null, string passWord = null)
        {
            try
            {
                var lsFileStruct = FtpHelper.GetFiles(ftpPath, withUser, userName, passWord);
                var aparentDir = new DirectoryInfo(parentDir.FullName + @"\" + dirName);
                if (!aparentDir.Exists)
                    aparentDir = parentDir.CreateSubdirectory(dirName);
                foreach (var fileStruct in lsFileStruct)
                {
                    if (fileStruct.FileType == PathType.File)
                    {
                        var filePath = aparentDir.FullName + @"\" + fileStruct.FileName;
                        DownFile(fileStruct.FilePath, filePath, withUser, userName, passWord);
                    }
                    else if (fileStruct.FileType == PathType.Dir)
                        DownFtpDir(fileStruct.FilePath, fileStruct.FileName, aparentDir, withUser, userName, passWord);
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// 
        /// 获取当前目录下所有的文件和目录信息
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static List GetFiles(string ftpPath, bool withUser = false, string userName = null, string passWord = null)
        {
            try
            {
                FtpWebRequest ftpWebRequest = CreateFtpRequest(ftpPath,withUser,userName,passWord);
                WebResponse response = ftpWebRequest.GetResponse();
                var responseStream = response.GetResponseStream();

                List strs = new List();
                //由于偶然性读取网络流出错,借助MemoryStream处理
                var memoryStream = new MemoryStream();
                int RequestCount = 1;
                while(true)
                {
                    try
                    {
                        responseStream.CopyTo(memoryStream);
                        break;
                    }
                    catch(Exception)  //由于请求一次出错(经测试如果请求过快或者目录下内容较小,会读取流出错),避免偶发性请求出错,可以请求多次(这里设置为5次)
                    {
                        RequestCount++;
                        if (RequestCount > 5)
                            throw;
                        responseStream = CreateFtpRequest(ftpPath, withUser, userName, passWord).GetResponse().GetResponseStream();
                        memoryStream.Dispose();
                        memoryStream = new MemoryStream();
                        continue;
                    }
                }
                memoryStream.Position = 0;  //需要设置起点为0
                using (var aReader = new StreamReader(memoryStream))
                {
                    var line = aReader.ReadLine();
                    while(line != null)
                    {
                        if (line.Contains(""))
                        {
                            string msg = line.Substring(line.LastIndexOf("") + 5).Trim();
                            strs.Add(new FileStruct() { FileType = PathType.Dir, FilePath = ftpPath + "/" + msg, FileName = msg });
                        }
                        else
                        {
                            string msg = line.Substring(39);
                            strs.Add(new FileStruct() { FileType = PathType.File, FilePath = ftpPath + "/" + msg, FileName = msg });
                        }
                        line = aReader.ReadLine();
                    }
                }
                memoryStream.Close();
                return strs;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("获取目录数据出错,原因:" + ex.Message + "\n目录:" + ftpPath);
                throw new Exception("远程主机无响应,下载目录信息出错");
            }
        }

        /// 
        /// 从ftp下载文件至本地路径
        /// 
        /// 
        /// 
        /// 是否使用用户名
        /// 
        /// 
        public static void DownFile(string ftpPath, string filePath, bool withUser = false, string userName = null, string passWord = null)
        {
            try
            {
                FtpWebRequest ftpWebRequest = CreateDownFtpRequest(ftpPath, withUser, userName, passWord);
                WebResponse response = ftpWebRequest.GetResponse();
                var respondStream = response.GetResponseStream();
                using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite))
                {
                    byte[] buffer = new byte[1024];
                    int bytesRead = 0;

                    int requstCount = 1; //文件下载失败,重新请求次数
                    while (true)
                    {
                        try
                        {
                            bytesRead = respondStream.Read(buffer, 0, buffer.Length);
                        }
                        catch (Exception) //与请求目录同理
                        {
                            if (requstCount > 5)
                                throw;
                            requstCount++;
                            respondStream = FtpHelper.CreateDownFtpRequest(ftpPath, withUser, userName, passWord).GetResponse().GetResponseStream();
                            bytesRead = 0;
                            fileStream.Position = 0;
                            continue;
                        }
                        if (bytesRead == 0)
                            break;
                        fileStream.Write(buffer, 0, bytesRead);
                    }
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.Write("从ftp服务器下载文件出错,文件名:" + ftpPath + "原因:" + ex.ToString());
                throw new Exception("下载文件至本地出错");
            }
        }

        /// 
        /// 构建获取目录请求
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static FtpWebRequest CreateFtpRequest(string ftpPath, bool withUser = false, string userName = null, string passWord = null)
        {
            FtpWebRequest ftpWebRequest;
            if (!Uri.TryCreate(ftpPath, UriKind.Absolute, out Uri ftpUri))
            {
                throw new Exception(ftpPath + "无效");
            }
            ftpWebRequest = (FtpWebRequest)FtpWebRequest.CreateDefault(ftpUri);
            ftpWebRequest.Timeout = 60000;
            ftpWebRequest.ReadWriteTimeout = 5000;
            ftpWebRequest.EnableSsl = false;
            ftpWebRequest.UseBinary = true;
            ftpWebRequest.KeepAlive = false;
            if (withUser)
                ftpWebRequest.Credentials = new NetworkCredential(userName, passWord);
            ftpWebRequest.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
            return ftpWebRequest;
        }

        /// 
        /// 构建下载文件请求
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static FtpWebRequest CreateDownFtpRequest(string ftpPath, bool withUser = false, string userName = null, string passWord = null)
        {
            FtpWebRequest ftpWebRequest;
            if (!Uri.TryCreate(ftpPath, UriKind.Absolute, out Uri ftpUri))
            {
                throw new Exception(ftpPath + "无效");
            }

            ftpWebRequest = (FtpWebRequest)FtpWebRequest.CreateDefault(ftpUri);
            ftpWebRequest.EnableSsl = false;

            System.Diagnostics.Debug.WriteLine(ftpPath);
            ftpWebRequest.Timeout = 30000;
            ftpWebRequest.ReadWriteTimeout = 10000;
            ftpWebRequest.UseBinary = true;
            ftpWebRequest.KeepAlive = false;
            if (withUser)
                ftpWebRequest.Credentials = new NetworkCredential(userName, passWord);
            ftpWebRequest.Method = WebRequestMethods.Ftp.DownloadFile;
            return ftpWebRequest;
        }
    }
}

基本的思路如下:

获取当前目录下的文件和目录信息,处理当前目录下文件和目录。如果是目录,则递归同样出路当前目录信息;如果是文件,则下载文件至目录保存。

值得一说的是,在实现的过程中,当请求很多的时候,在读取响应流会在偶然出现“ 请求一方没有响应“的错误。通过查询知道原因大概是当流为空的时候,读取流的对象会自动把流断开,参考https://stackoverflow.com/questions/48829032/streamreader-readline-throwing-disposed-exception-rather-than-returning-null。 因此,避免偶然读取流断开就报错的异常,多请求几次,确定是服务器问题才报错。处理方法就是有注释(try...catch{})那段。

类库使用的话,直接FtpHelper.DownFtpDir(参数), 即能调用下载目录下所有文件。

注意点:如果目录下存在相同的文件,则会覆盖。如果不用覆盖,可以自行处理。

本文提取至完整下载功能(包含ftp目录树加载,下载进度显示,下载速度显示)一部分。需要完整代码可以私聊

qq1754630968

你可能感兴趣的:(C#,Ftp文件下载,客户端开发,C#,Ftp下载目录下所有文件,Ftp文件下载)