Ftp 上傳下載操作C# 類

黑燈舞 9年前發布 | 2K 次閱讀 C# FTP

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;

namespace AppUtility { /// <summary> /// FTP Client /// </summary> public class FTPClient {

    #region 構造函數
    /// <summary>
    /// 缺省構造函數
    /// </summary>
    public FTPClient()
    {
        strRemoteHost  = "";
        strRemotePath  = "";
        strRemoteUser  = "";
        strRemotePass  = "";
        strRemotePort  = 21;
        bConnected     = false;
    }

    /// <summary>
    /// 構造函數
    /// </summary>
    /// <param name="remoteHost"></param>
    /// <param name="remotePath"></param>
    /// <param name="remoteUser"></param>
    /// <param name="remotePass"></param>
    /// <param name="remotePort"></param>
    public FTPClient( string remoteHost, string remotePath, string remoteUser, string remotePass, int remotePort )
    {
        strRemoteHost  = remoteHost;
        strRemotePath  = remotePath;
        strRemoteUser  = remoteUser;
        strRemotePass  = remotePass;
        strRemotePort  = remotePort;
        Connect();
    }
    #endregion

    #region 登陸
    /// <summary>
    /// FTP服務器IP地址
    /// </summary>
    private string strRemoteHost;
    public string RemoteHost
    {
        get
        {
            return strRemoteHost;
        }
        set
        {
            strRemoteHost = value;
        }
    }
    /// <summary>
    /// FTP服務器端口
    /// </summary>
    private int strRemotePort;
    public int RemotePort
    {
        get
        {
        return strRemotePort;
        }
        set
        {
            strRemotePort = value;
        }
    }
    /// <summary>
    /// 當前服務器目錄
    /// </summary>
    private string strRemotePath;
    public string RemotePath
    {
        get
        {
            return strRemotePath;
        }
        set
        {
            strRemotePath = value;
        }
    }
    /// <summary>
    /// 登錄用戶賬號
    /// </summary>
    private string strRemoteUser;
    public string RemoteUser
    {
        set
        {
            strRemoteUser = value;
        }
    }
    /// <summary>
    /// 用戶登錄密碼
    /// </summary>
    private string strRemotePass;
    public string RemotePass
    {
        set
        {
            strRemotePass = value;
        }
    }

    /// <summary>
    /// 是否登錄
    /// </summary>
    private Boolean bConnected;
    public bool Connected
    {
        get
        {
            return bConnected;
        }
    }
    #endregion

    #region 鏈接
    /// <summary>
    /// 建立連接 
    /// </summary>
    public void Connect()
    {
        socketControl = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
        IPEndPoint ep = new IPEndPoint(IPAddress.Parse(RemoteHost), strRemotePort);
        // 鏈接
        try
        {
            socketControl.Connect(ep);
        }
        catch(Exception)
        {
            throw new IOException("Couldn't connect to remote server");
        }

        // 獲取應答碼
        ReadReply();
        if(iReplyCode != 220)
        {
            DisConnect();
            throw new IOException(strReply.Substring(4));
        }

        // 登陸
        SendCommand("USER "+strRemoteUser);
        if( !(iReplyCode == 331 || iReplyCode == 230) )
        {
            CloseSocketConnect();//關閉連接
            throw new IOException(strReply.Substring(4));
        }
        if( iReplyCode != 230 )
        {
            SendCommand("PASS "+strRemotePass);
            if( !(iReplyCode == 230 || iReplyCode == 202) )
            {
                 CloseSocketConnect();//關閉連接
                 throw new IOException(strReply.Substring(4));
            }
        }
        bConnected = true;

        // 切換到目錄
        ChDir(strRemotePath);
    }

    /// <summary>
    /// 關閉連接
    /// </summary>
    public void DisConnect()
    {
        if( socketControl != null )
        {
            SendCommand("QUIT");
        }
        CloseSocketConnect();
    }

    #endregion

    #region 傳輸模式

    /// <summary>
    /// 傳輸模式:二進制類型、ASCII類型
    /// </summary>
    public enum TransferType {Binary,ASCII};

    /// <summary>
    /// 設置傳輸模式
    /// </summary>
    /// <param name="ttType">傳輸模式</param>
    public void SetTransferType(TransferType ttType)
    {
        if(ttType == TransferType.Binary)
        {
            SendCommand("TYPE I");//binary類型傳輸
        }
        else
        {
            SendCommand("TYPE A");//ASCII類型傳輸
        }
        if (iReplyCode != 200)
        {
            throw new IOException(strReply.Substring(4));
        }
        else
        {
            trType = ttType;
        }
    }

    /// <summary>
    /// 獲得傳輸模式
    /// </summary>
    /// <returns>傳輸模式</returns>
    public TransferType GetTransferType()
    {
        return trType;
    }

    #endregion

    #region 文件操作
    /// <summary>
    /// 獲得文件列表
    /// </summary>
    /// <param name="strMask">文件名的匹配字符串</param>
    /// <returns></returns>
    public string[] Dir(string strMask)
    {
        // 建立鏈接
        if(!bConnected)
        {
            Connect();
        }

        //建立進行數據連接的socket
        Socket socketData = CreateDataSocket();

        //傳送命令
        SendCommand("NLST " + strMask);

        //分析應答代碼
        if(!(iReplyCode == 150 || iReplyCode == 125 || iReplyCode == 226))
        {
            throw new IOException(strReply.Substring(4));
        }

        //獲得結果
        strMsg = "";
        while(true)
        {
            int iBytes = socketData.Receive(buffer, buffer.Length, 0);
            strMsg += ASCII.GetString(buffer, 0, iBytes);
            if(iBytes < buffer.Length)
            {
                break;
            }
        }
        char[] seperator = {' '};
        string[] strsFileList = strMsg.Split(seperator);
        socketData.Close();//數據socket關閉時也會有返回碼
        if(iReplyCode != 226)
        {
            ReadReply();
            if(iReplyCode != 226)
            {
                throw new IOException(strReply.Substring(4));
            }
        }
        return strsFileList;
    }

    /// <summary>
    /// 獲取文件大小
    /// </summary>
    /// <param name="strFileName">文件名</param>
    /// <returns>文件大小</returns>
    private long GetFileSize(string strFileName)
    {
        if(!bConnected)
        {
            Connect();
        }
        SendCommand("SIZE " + Path.GetFileName(strFileName));
        long lSize=0;
        if(iReplyCode == 213)
        {
            lSize = Int64.Parse(strReply.Substring(4));
        }
        else
        {
            throw new IOException(strReply.Substring(4));
        }
        return lSize;
    }

    /// <summary>
    /// 刪除
    /// </summary>
    /// <param name="strFileName">待刪除文件名</param>
    public void Delete(string strFileName)
    {
        if(!bConnected)
        {
            Connect();
        }
        SendCommand("DELE "+strFileName);
        if(iReplyCode != 250)
        {
            throw new IOException(strReply.Substring(4));
        }
    }

    /// <summary>
    /// 重命名(如果新文件名與已有文件重名,將覆蓋已有文件)
    /// </summary>
    /// <param name="strOldFileName">舊文件名</param>
    /// <param name="strNewFileName">新文件名</param>
    public void Rename(string strOldFileName,string strNewFileName)
    {
        if(!bConnected)
        {
            Connect();
        }
        SendCommand("RNFR "+strOldFileName);
        if(iReplyCode != 350)
        {
            throw new IOException(strReply.Substring(4));
        }
        //  如果新文件名與原有文件重名,將覆蓋原有文件
        SendCommand("RNTO "+strNewFileName);
        if(iReplyCode != 250)
        {
            throw new IOException(strReply.Substring(4));
        }
    }
    #endregion

    #region 上傳和下載
    /// <summary>
    /// 下載一批文件
    /// </summary>
    /// <param name="strFileNameMask">文件名的匹配字符串</param>
    /// <param name="strFolder">本地目錄(不得以結束)</param>
    public void Get(string strFileNameMask,string strFolder)
    {
        if(!bConnected)
        {
            Connect();
        }
        string[] strFiles = Dir(strFileNameMask);
        foreach(string strFile in strFiles)
        {
            if(!strFile.Equals(""))//一般來說strFiles的最后一個元素可能是空字符串
            {
                Get(strFile,strFolder,strFile);
            }
        }
    }

    /// <summary>
    /// 下載一個文件
    /// </summary>
    /// <param name="strRemoteFileName">要下載的文件名</param>
    /// <param name="strFolder">本地目錄(不得以結束)</param>
    /// <param name="strLocalFileName">保存在本地時的文件名</param>
    public void Get(string strRemoteFileName,string strFolder,string strLocalFileName)
    {
        if(!bConnected)
        {
            Connect();
        }
        SetTransferType(TransferType.Binary);
        if (strLocalFileName.Equals(""))
        {
            strLocalFileName = strRemoteFileName;
        }
        if(!File.Exists(strLocalFileName))
        {
            Stream st = File.Create(strLocalFileName);
            st.Close();
        }
        FileStream output = new 
        FileStream(strFolder + "\"" + strLocalFileName,FileMode.Create);
        Socket socketData = CreateDataSocket();
        SendCommand("RETR " + strRemoteFileName);
        if(!(iReplyCode == 150 || iReplyCode == 125
            || iReplyCode == 226 || iReplyCode == 250))
        {
            throw new IOException(strReply.Substring(4));
        }
        while(true)
        {
            int iBytes = socketData.Receive(buffer, buffer.Length, 0);
            output.Write(buffer,0,iBytes);
            if(iBytes <= 0)
            {
                break;
            }
        }
        output.Close();
        if (socketData.Connected)
        {
            socketData.Close();
        }
        if(!(iReplyCode == 226 || iReplyCode == 250))
        {
            ReadReply();
            if(!(iReplyCode == 226 || iReplyCode == 250))
            {
                throw new IOException(strReply.Substring(4));
            }
        }
    }

    /// <summary>
    /// 上傳一批文件
    /// </summary>
    /// <param name="strFolder">本地目錄(不得以結束)</param>
    /// <param name="strFileNameMask">文件名匹配字符(可以包含*和?)</param>
    public void Put(string strFolder,string strFileNameMask)
    {
        string[] strFiles = Directory.GetFiles(strFolder,strFileNameMask);
        foreach(string strFile in strFiles)
        {
            //strFile是完整的文件名(包含路徑)
            Put(strFile);
        }
    }

    /// <summary>
    /// 上傳一個文件
    /// </summary>
    /// <param name="strFileName">本地文件名</param>
    public void Put(string strFileName)
    {
        if(!bConnected)
        {
            Connect();
        }
        Socket socketData = CreateDataSocket();
        SendCommand("STOR "+Path.GetFileName(strFileName));
        if( !(iReplyCode == 125 || iReplyCode == 150) )
        {
            throw new IOException(strReply.Substring(4));
        }
        FileStream input = new 
        FileStream(strFileName,FileMode.Open);
        int iBytes = 0;
        while ((iBytes = input.Read(buffer,0,buffer.Length)) > 0)
        {
            socketData.Send(buffer, iBytes, 0);
        }
        input.Close();
        if (socketData.Connected)
        {
            socketData.Close();
        }
        if(!(iReplyCode == 226 || iReplyCode == 250))
        {
            ReadReply();
            if(!(iReplyCode == 226 || iReplyCode == 250))
            {
                throw new IOException(strReply.Substring(4));
            }
        }
    }

    #endregion

    #region 目錄操作
    /// <summary>
    /// 創建目錄
    /// </summary>
    /// <param name="strDirName">目錄名</param>
    public void MkDir(string strDirName)
    {
        if(!bConnected)
        {
            Connect();
        }
        SendCommand("MKD "+strDirName);
        if(iReplyCode != 257)
        {
            throw new IOException(strReply.Substring(4));
        }
    }

    /// <summary>
    /// 刪除目錄
    /// </summary>
    /// <param name="strDirName">目錄名</param>
    public void RmDir(string strDirName)
    {
        if(!bConnected)
        {
            Connect();
        }
        SendCommand("RMD "+strDirName);
        if(iReplyCode != 250)
        {
            throw new IOException(strReply.Substring(4));
        }
    }

    /// <summary>
    /// 改變目錄
    /// </summary>
    /// <param name="strDirName">新的工作目錄名</param>
    public void ChDir(string strDirName)
    {
        if(strDirName.Equals(".") || strDirName.Equals(""))
        {
            return;
        }
        if(!bConnected)
        {
            Connect();
        }
        SendCommand("CWD "+strDirName);
        if(iReplyCode != 250)
        {
            throw new IOException(strReply.Substring(4));
        }
        this.strRemotePath = strDirName;
    }

    #endregion

    #region 內部變量
    /// <summary>
    /// 服務器返回的應答信息(包含應答碼)
    /// </summary>
    private string strMsg;
    /// <summary>
    /// 服務器返回的應答信息(包含應答碼)
    /// </summary>
    private string strReply;
    /// <summary>
    /// 服務器返回的應答碼
    /// </summary>
    private int iReplyCode;
    /// <summary>
    /// 進行控制連接的socket
    /// </summary>
    private Socket socketControl;
    /// <summary>
    /// 傳輸模式
    /// </summary>
    private TransferType trType;
    /// <summary>
    /// 接收和發送數據的緩沖區
    /// </summary>
    private static int BLOCK_SIZE = 512;
    Byte[] buffer = new Byte[BLOCK_SIZE];
    /// <summary>
    /// 編碼方式
    /// </summary>
    Encoding ASCII = Encoding.ASCII;
    #endregion

    #region 內部函數
    /// <summary>
    /// 將一行應答字符串記錄在strReply和strMsg
    /// 應答碼記錄在iReplyCode
    /// </summary>
    private void ReadReply()
    {
        strMsg = "";
        strReply = ReadLine();
        iReplyCode = Int32.Parse(strReply.Substring(0,3));
    }

    /// <summary>
    /// 建立進行數據連接的socket
    /// </summary>
    /// <returns>數據連接socket</returns>
    private Socket CreateDataSocket()
    {
        SendCommand("PASV");
        if(iReplyCode != 227)
        {
            throw new IOException(strReply.Substring(4));
        }
        int index1 = strReply.IndexOf('(');
        int index2 = strReply.IndexOf(')');
        string ipData = 
        strReply.Substring(index1+1,index2-index1-1);
        int[] parts = new int[6];
        int len = ipData.Length;
        int partCount = 0;
        string buf="";
        for (int i = 0; i < len && partCount <= 6; i++)
        {
            char ch = Char.Parse(ipData.Substring(i,1));
            if (Char.IsDigit(ch))
                buf+=ch;
            else if (ch != ',')
            {
                throw new IOException("Malformed PASV strReply: " + 
                strReply);
            }
            if (ch == ',' || i+1 == len)
            {
                try
                {
                    parts[partCount++] = Int32.Parse(buf);
                    buf="";
                }
                catch (Exception)
                {
                    throw new IOException("Malformed PASV strReply: " + 
                    strReply);
                }
            }
        }

        string ipAddress = parts[0] + "."+ parts[1]+ "." +
        parts[2] + "." + parts[3];
        int port = (parts[4] << 8) + parts[5];
        Socket s = new 
        Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
        IPEndPoint ep = new 
        IPEndPoint(IPAddress.Parse(ipAddress), port);
        try
        {
            s.Connect(ep);
        }
        catch(Exception)
        {
            throw new IOException("Can't connect to remote server");
        }
        return s;
    }

    /// <summary>
    /// 關閉socket連接(用于登錄以前)
    /// </summary>
    private void CloseSocketConnect()
    {
        if(socketControl!=null)
        {
            socketControl.Close();
            socketControl = null;
        }
        bConnected = false;
    }

    /// <summary>
    /// 讀取Socket返回的所有字符串
    /// </summary>
    /// <returns>包含應答碼的字符串行</returns>
    private string ReadLine()
    {
        while(true)
        {
            int iBytes = socketControl.Receive(buffer, buffer.Length, 0);
            strMsg += ASCII.GetString(buffer, 0, iBytes);
            if(iBytes < buffer.Length)
            {
                break;
            }
        }
        char[] seperator = {' '};
        string[] mess = strMsg.Split(seperator);
        if(strMsg.Length > 2)
        {
            strMsg = mess[mess.Length-2];
        //seperator[0]是10,換行符是由13和0組成的,分隔后10后面雖沒有字符串,
        //但也會分配為空字符串給后面(也是最后一個)字符串數組,
        //所以最后一個mess是沒用的空字符串
        //但為什么不直接取mess[0],因為只有最后一行字符串應答碼與信息之間有空格
        }
        else
        {
            strMsg = mess[0];
        }
        if(!strMsg.Substring(3,1).Equals(" "))//返回字符串正確的是以應答碼(如220開頭,后面接一空格,再接問候字符串)
        {
            return ReadLine();
        }
        return strMsg;
    }

    /// <summary>
    /// 發送命令并獲取應答碼和最后一行應答字符串
    /// </summary>
    /// <param name="strCommand">命令</param>
    private void SendCommand(String strCommand)
    {
        Byte[] cmdBytes = 
        Encoding.ASCII.GetBytes((strCommand+" ").ToCharArray());
        socketControl.Send(cmdBytes, cmdBytes.Length, 0);
        ReadReply();
    }

    #endregion
}

}</pre>

 本文由用戶 黑燈舞 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!