C#打造自己的FTP传输软件【原理篇】

本文介绍如何使用C#构建FTP客户端,包括连接服务器、获取文件列表、上传下载文件、创建删除目录等操作。通过FtpWebRequest类,遵循‘请求-响应’模式实现FTP交互。提供完整代码示例,适合初学者实践。

最近由于工作需要,

“被迫”研究了一下C#处理FTP操作的一些问题。

在此与大家共享。

 

其实相当简单的,今天我先把原理的代码发给大家看一下。

我建议有兴趣的,可以加强一下功能,做个FTP软件,或是“FTP资源管理器”,这样不是很好吗?

OK,废话不多说,开始!

 

 

其实呢,说到底,再说到底,再往底说,

FTP操作也还是脱离不了“请求、响应”之模式。

请求自然是Request,响应则是Response。

所以,我们要先认识认识FtpWebRequst这个类了。

【附:MSDN官方记录 http://msdn.microsoft.com/zh-cn/library/system.net.ftpwebrequest.aspx

建议初学者参考一下MSDN,但不建议您看明白。

没错, 不明白很正常。别担心。

多说无益,拉出来练练吧。

 OK,说得再好听,也不如用代码实现之!

代码大体结构如此,后面会详细介绍。

#region 属性列表Properties

 

/// <summary>

/// 服务器地址,可以是IP,也可以是FTP网址

/// </summary>

private string FtpServerAddress;

 

/// <summary>

/// 用户名

/// </summary>

private string FtpUserName;

 

/// <summary>

/// 用户密码

/// </summary>

private string FtpPassword;

 

/// <summary>

/// FTP请求

/// </summary>

private FtpWebRequest ftpRequest;

 

#endregion

 

#region 构造函数Structure

 

public FtpUpDown(string ftpServer, string ftpUserName, string ftpPassword)

    :this(ftpServer,ftpUserName,ftpPassword,0)

{ }

 

/// <summary>

/// FTP上传下载

/// </summary>

/// <param name="ftpServer">服务器IP</param>

/// <param name="ftpUserName">用户名</param>

/// <param name="ftpPassword">密码</param>

/// <param name="ftpServerPort">服务器端口</param>

public FtpUpDown(string ftpServer, string ftpUserName, string ftpPassword,int ftpServerPort)

{

    this.FtpServerAddress = ftpServer;

    this.FtpUserName = ftpUserName;

    this.FtpPassword = ftpPassword;

 

    //如果端口号大于零,则代表已经指定了端口号,否则使用默认端口。

    this.FtpServerAddress += (ftpServerPort > 0 ? string.Format(":{0}", ftpServerPort) : string.Empty);

}

 

#endregion

 

#region 私有方法Private methods

 

/// <summary>

/// 连接服务器

/// </summary>

private void Connect()

{

    Connect("ftp://" + FtpServerAddress + "/");

}

 

/// <summary>

/// 连接服务器

/// </summary>

/// <param name="path">FTP服务器要连接的路径</param>

private void Connect(String path)

{

    // 根据FTP路径创建FtpWebRequest对象

    ftpRequest = (FtpWebRequest)FtpWebRequest.Create(path);

    // 指定数据传输类型

    ftpRequest.UseBinary = true;

    //是否使用被动模式,主动FTP模式与被动FTP模式,可以参考下面的网页

    //http://blog.csdn.net/beijibingshan/archive/2007/06/14/1653004.aspx

    ftpRequest.UsePassive = false;

    // ftp用户名和密码,创建与FTP进行连接的凭证。

    ftpRequest.Credentials = new NetworkCredential(FtpUserName, FtpPassword);

}

 

/// <summary>

/// 获得指定目录中的文件列表

/// </summary>

/// <param name="path">指定目录</param>

/// <param name="WRMethods">发送到FTP服务器的命令【WebRequestMethods类中的值】</param>

/// <returns></returns>

private string[] GetFileList(string path, string WRMethods)

{

    //最终要返回的文件(或目录)列表

    List<string> fileList=new List<string>();

 

    try

    {

        //连接指定目录

        Connect(path);

        //确定要执行的方法【读取目录?还是......?在此指定。】

        ftpRequest.Method = WRMethods;

 

        //接收服务器响应

        WebResponse response = ftpRequest.GetResponse();

        StreamReader reader = new StreamReader(response.GetResponseStream(), System.Text.Encoding.Default);//中文文件名

        string line = reader.ReadLine();

        while (line != null)

        {

            //循环读取并记录响应内容

            fileList.Add(line);

 

            line = reader.ReadLine();

        }

       

        reader.Close();

        response.Close();

        return fileList.ToArray();

    }

    catch (Exception ex)

    {

        //抛出错误,谁调用谁处理,偶就是不管。

        throw ex;

    }

}

 

#endregion

 

#region 公共方法Public Methods

 

/// <summary>

/// 测试连接

/// </summary>

/// <returns>是否测试成功</returns>

public bool TestConnection()

{

    string errorInfo=string.Empty;

    return this.TestConnection(out errorInfo);

}

 

/// <summary>

/// 测试连接

/// </summary>

/// <param name="errorInfo">返回的错误信息</param>

/// <returns>是否测试成功</returns>

public bool TestConnection(out string errorInfo)

{

    errorInfo = string.Empty;

    try

    {

        //试图读取服务器端文件列表

        this.GetFileList();

 

        //读取成功,则代码连接无误

        return true;

    }

    catch (Exception ex)

    {

        //出错,则连接不对。

        errorInfo = "【连接错误】详细信息是:" + ex.Message;

        return false;

    }

}

 

/// <summary>

/// 从ftp服务器上获得根目录文件列表

/// </summary>

/// <returns></returns>

public string[] GetFileList()

{

    return GetFileList("ftp://" + FtpServerAddress + "/", WebRequestMethods.Ftp.ListDirectory);

}

 

/// <summary>

/// 从ftp服务器上获得文件列表

/// </summary>

/// <param name="path">请求的路径【相对路径】</param>

/// <returns></returns>

public string[] GetFileList(string path)

{

    return GetFileList("ftp://" + FtpServerAddress + "/" + path, WebRequestMethods.Ftp.ListDirectory);

}

 

/// <summary>

/// 向服务器上传文件

/// </summary>

/// <param name="filename">本地文件路径</param>

/// <param name="serverPath">服务器端的相对路径【例:uploads/myfiles 】两端不要加斜杠</param>

public void Upload(string filename, string serverPath)

{

    Upload(filename, serverPath, null);

}

 

/// <summary>

/// 向服务器上传文件

/// </summary>

/// <param name="filename">本地文件路径</param>

/// <param name="serverPath">服务器端的相对路径【例:uploads/myfiles 】两端不要加斜杠</param>

/// <param name="transProcess">传输进度</param>

public void Upload(string filename,string serverPath,TransmissionProcess transProcess)

{

    //检查传输进度

    if (transProcess==null)

    {

        transProcess = new TransmissionProcess();

    }

 

    FileInfo fileInf = new FileInfo(filename);

    string uri = string.Format("ftp://{0}/{1}/{2}", FtpServerAddress, serverPath, fileInf.Name);

 

    transProcess.FileName = uri;//文件名

    transProcess.TotalBytes = fileInf.Length;//文件大小

 

    Connect(uri);//连接        

    //默认为true,连接不会被关闭

    //在一个命令之后被执行

    ftpRequest.KeepAlive = false;

    //指定执行什么命令

    ftpRequest.Method = WebRequestMethods.Ftp.UploadFile;

    //上传文件时通知服务器文件的大小

    ftpRequest.ContentLength = fileInf.Length;

    //缓冲大小设置为kb

    int buffLength = 2048;

    byte[] buff = new byte[buffLength];

 

    //打开一个文件流(System.IO.FileStream) 去读上传的文件

    FileStream fs = fileInf.OpenRead();

 

    try

    {

        //把上传的文件写入流

        Stream strm = ftpRequest.GetRequestStream();

 

        //每次读文件流的byte数目

        int contentLen = fs.Read(buff, 0, buffLength);

 

        //流内容没有结束

        while (contentLen != 0)

        {

            //改变传输状态

            if (transProcess.TransStatus != TransferStatus.InTransit)

                transProcess.TransStatus = TransferStatus.InTransit;

 

            //把内容从file stream 写入upload stream

            strm.Write(buff, 0, contentLen);

 

            //通知追加进度

            transProcess.AppendBytes(contentLen);

 

            contentLen = fs.Read(buff, 0, buffLength);

        }

 

        //关闭两个流

        strm.Close();

        fs.Close();

 

        //传输结束

        transProcess.TransStatus = TransferStatus.TranFinished;

    }

    catch (Exception ex)

    {

        transProcess.TransStatus = TransferStatus.Failed;

        throw new Exception(string.Format("向服务器上传文件时出错!/n/n{0}", ex.Message));

    }

 

}

 

/// <summary>

/// 从ftp服务器下载文件

/// </summary>

/// <param name="filePath">要保存文件的本地目录</param>

/// <param name="fileName">远程文件的路径【示例:uploads/myfile.rar】</param>

/// <param name="overWriteLocalFile">是否覆盖本地文件</param>

/// <param name="errorinfo">下载失败时,输出的错误信息</param>

/// <returns>是否下载成功</returns>

public bool Download(string filePath, string fileName, bool overWriteLocalFile, out string errorinfo)

{

    return Download(filePath, fileName, overWriteLocalFile, null, out errorinfo);

}

 

/// <summary>

/// 从ftp服务器下载文件

/// </summary>

/// <param name="filePath">要保存文件的本地目录</param>

/// <param name="fileName">远程文件的路径【示例:uploads/myfile.rar】</param>

/// <param name="overWriteLocalFile">是否覆盖本地文件</param>

/// <param name="transProcess">传输进度</param>

/// <param name="errorinfo">下载失败时,输出的错误信息</param>

/// <returns>是否下载成功</returns>

public bool Download(string filePath, string fileName, bool overWriteLocalFile,TransmissionProcess transProcess, out string errorinfo)

{

    //检查传输进度

    if (transProcess == null)

    {

        transProcess = new TransmissionProcess();

    }

 

    errorinfo = string.Empty;

    try

    {

        String onlyFileName = Path.GetFileName(fileName);

 

        string newFileName = filePath + "//" + onlyFileName;

 

        if (File.Exists(newFileName) && overWriteLocalFile == false)

        {

            transProcess.TransStatus = TransferStatus.Failed;

            errorinfo = string.Format("本地文件{0}已存在,无法下载", newFileName);

            return false;

        }

 

        //检查本地文件是否被占用

        if (File.Exists(newFileName))

        {

            try

            {

                File.Move(newFileName, newFileName);

            }

            catch

            {

                transProcess.TransStatus = TransferStatus.Failed;

                errorinfo = "本地文件被占用!无法覆盖!";

                return false;

            }

        }

 

        string url = "ftp://" + FtpServerAddress + "/" + fileName;

        Connect(url);//连接

        ftpRequest.Credentials = new NetworkCredential(FtpUserName, FtpPassword);

        FtpWebResponse response = (FtpWebResponse)ftpRequest.GetResponse();

        Stream ftpStream = response.GetResponseStream();

        long cl = response.ContentLength;

        int bufferSize = 2048;

        int readCount;

        byte[] buffer = new byte[bufferSize];

 

        transProcess.FileName = url;

        transProcess.TotalBytes = cl;

        //改变传输状态

        if (transProcess.TransStatus != TransferStatus.InTransit)

            transProcess.TransStatus = TransferStatus.InTransit;

 

        readCount = ftpStream.Read(buffer, 0, bufferSize);

        transProcess.AppendBytes(readCount);

 

        FileStream outputStream = new FileStream(newFileName, FileMode.Create, FileAccess.Write);

        while (readCount > 0)

        {

            outputStream.Write(buffer, 0, readCount);

            readCount = ftpStream.Read(buffer, 0, bufferSize);

            transProcess.AppendBytes(readCount);

        }

        ftpStream.Close();

        outputStream.Close();

        response.Close();

 

        //完成传输

        transProcess.FinishBytes();

 

        //下载成功

        return true;

    }

    catch (Exception ex)

    {

        transProcess.TransStatus = TransferStatus.Failed;

        errorinfo = string.Format("因{0},无法下载", ex.Message);

        return false;

    }

}

 

/// <summary>

/// 删除指定文件

/// </summary>

/// <param name="fileName">远程文件的路径【示例:uploads/myfile.rar】</param>

public void DeleteFileName(string fileName)

{

    string uri = "ftp://" + FtpServerAddress + "/" + fileName;

    try

    {

        Connect(uri);//连接       

 

        // 默认为true,连接不会被关闭

        // 在一个命令之后被执行

        ftpRequest.KeepAlive = false;

 

        // 指定执行什么命令

        ftpRequest.Method = WebRequestMethods.Ftp.DeleteFile;

        FtpWebResponse response = (FtpWebResponse)ftpRequest.GetResponse();

        response.Close();

    }

    catch (Exception ex)

    {

        throw new Exception(string.Format("删除文件"{0}"时出错!/n/n{1}", uri, ex.Message));

    }

}

 

/// <summary>

/// 创建远程目录

/// </summary>

/// <param name="dirPath">远程文件夹路径</param>

/// <returns></returns>

public bool CreateDirectory(string dirPath)

{

    try

    {

        string dirUri = "ftp://" + FtpServerAddress + "/" + dirPath;

        this.Connect(dirUri);

        ftpRequest.KeepAlive = false;

        ftpRequest.Method = WebRequestMethods.Ftp.MakeDirectory;

        ftpRequest.Proxy = null;

        FtpWebResponse uploadResponse = (FtpWebResponse)ftpRequest.GetResponse();

        uploadResponse.Close();

        return true;

    }

    catch(Exception ex)

    {

        Console.WriteLine(ex.Message);

        return false;

    }

}

 

/// <summary>

/// 删除目录

/// </summary>

/// <param name="dirPath">远程文件夹名【例如:uploads/oldDir】</param>

/// <returns></returns>

public bool DeleteDirectory(string dirPath)

{

    try

    {

        string uri = "ftp://" + FtpServerAddress + "/" + dirPath;

        Connect(uri);//连接

        ftpRequest.Method = WebRequestMethods.Ftp.RemoveDirectory;

        FtpWebResponse response = (FtpWebResponse)ftpRequest.GetResponse();

        response.Close();

 

        return true;

    }

    catch (Exception ex)

    {

        Console.WriteLine(ex.Message);

        return false;

    }

}

 

/// <summary>

/// 获得文件大小

/// </summary>

/// <param name="filename">远程文件的路径【示例:uploads/myfile.rar】</param>

/// <returns></returns>

public long GetFileSize(string filename)

{

    long fileSize = 0;

    string uri = "ftp://" + FtpServerAddress + "/" + filename;

 

    try

    {

        Connect(uri);//连接

        ftpRequest.Method = WebRequestMethods.Ftp.GetFileSize;

        FtpWebResponse response = (FtpWebResponse)ftpRequest.GetResponse();

        fileSize = response.ContentLength;

        response.Close();

    }

    catch (Exception ex)

    {

        throw new Exception(string.Format("获得文件"{0}"大小时出错!/n/n{1}", uri, ex.Message));

    }

 

    //成功返回大小

    return fileSize;

}

 

/// <summary>

/// 重命名文件

/// </summary>

/// <param name="currentFilename">远程文件的路径【示例:uploads/myfile.rar】</param>

/// <param name="newFilename">新名【不需要路径,但要包含后缀】</param>

public void Rename(string currentFilename, string newFilename)

{

    string uri = "ftp://" + FtpServerAddress + "/" + currentFilename;

    try

    {

        Connect(uri);//连接

        ftpRequest.Method = WebRequestMethods.Ftp.Rename;

        ftpRequest.RenameTo = newFilename;

 

        FtpWebResponse response = (FtpWebResponse)ftpRequest.GetResponse();

        response.Close();

    }

    catch (Exception ex)

    {

        throw new Exception(string.Format("重命名文件"{0}"大小时出错!/n/n{1}", uri, ex.Message));

    }

}

 

/// <summary>

/// 获得根目录文件明晰

/// </summary>

/// <returns></returns>

public string[] GetFilesDetailList()

{

    return GetFilesDetailList(string.Empty);

}

 

/// <summary>

/// 获得指定目录中的文件明晰

/// </summary>

/// <param name="path">指定目录【示例:upload/yan】</param>

/// <returns></returns>

public string[] GetFilesDetailList(string path)

{

    return GetFileList("ftp://" + FtpServerAddress + "/" + path, WebRequestMethods.Ftp.ListDirectoryDetails);

}

 

#endregion

有想要整个源码的,到这里下载
http://yanmang.download.csdn.net/

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

颜氓

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值