csharp: FTP Client Library using System.Net.FtpWebRequest

来源:http://www.cnblogs.com/geovindu/archive/2017/08/02/7274715.html
-Advertisement-
Play Games

測試代碼: ...


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Collections;
using Microsoft.VisualBasic;
using System.Net;
using System.IO;
using System.Text.RegularExpressions;
using System.Windows.Forms;
//https://www.codeproject.com/Articles/56321/A-Windows-FTP-Application
//https://www.codeproject.com/Articles/4472/Enhanced-BrowseForFolder-styled-TreeView
//https://github.com/ChrisRichner/TreeViewFolderBrowser
//https://www.codeproject.com/Articles/11991/An-FTP-client-library-for-NET
//https://github.com/aybe/Windows-API-Code-Pack-1.1
//https://github.com/dbarros/WindowsAPICodePack

namespace FTPLibrary
{
    #region "FTP client class"
    /// <summary>
    /// A wrapper class for .NET 2.0 FTP
    /// </summary>
    /// <remarks>
    /// This class does not hold open an FTP connection but
    /// instead is stateless: for each FTP request it
    /// connects, performs the request and disconnects.
    /// </remarks>
    public class FTPclient
    {
        #region Delegated & Events
        //Download Progress Changed Event
        public delegate void DownloadProgressChangedHandler(object sender, DownloadProgressChangedArgs e);
        public event DownloadProgressChangedHandler OnDownloadProgressChanged;

        //Download Completed Event
        public delegate void DownloadCompletedHandler(object sender, DownloadCompletedArgs e);
        public event DownloadCompletedHandler OnDownloadCompleted;

        //New Server Message Event
        public delegate void NewMessageHandler(object sender, NewMessageEventArgs e);
        public event NewMessageHandler OnNewMessageReceived;

        //Upload Progress Changed Event
        //Download Progress Changed Event
        public delegate void UploadProgressChangedHandler(object sender, UploadProgressChangedArgs e);
        public event UploadProgressChangedHandler OnUploadProgressChanged;

        //Upload Completed Event
        public delegate void UploadCompletedHandler(object sender, UploadCompletedArgs e);
        public event UploadCompletedHandler OnUploadCompleted;
        #endregion

        #region "CONSTRUCTORS"
        /// <summary>
        /// Blank constructor
        /// </summary>
        /// <remarks>Hostname, username and password must be set manually</remarks>
        public FTPclient()
        {
        }

        /// <summary>
        /// Constructor just taking the hostname
        /// </summary>
        /// <param name="Hostname">in either ftp://ftp.host.com or ftp.host.com form</param>
        /// <remarks></remarks>
        public FTPclient(string Hostname)
        {
            _hostname = Hostname;
        }

        /// <summary>
        /// Constructor taking hostname, username and password
        /// </summary>
        /// <param name="Hostname">in either ftp://ftp.host.com or ftp.host.com form</param>
        /// <param name="Username">Leave blank to use 'anonymous' but set password to your email</param>
        /// <param name="Password"></param>
        /// <remarks></remarks>
        public FTPclient(string Hostname, string Username, string Password)
        {
            _hostname = Hostname;
            _username = Username;
            _password = Password;
        }
        #endregion

        #region "Directory functions"
        /// <summary>
        /// Return a simple directory listing
        /// </summary>
        /// <param name="directory">Directory to list, e.g. /pub</param>
        /// <returns>A list of filenames and directories as a List(of String)</returns>
        /// <remarks>For a detailed directory listing, use ListDirectoryDetail</remarks>
        public List<string> ListDirectory(string directory)
        {
            //return a simple list of filenames in directory
            System.Net.FtpWebRequest ftp = GetRequest(GetDirectory(directory));
            //Set request to do simple list
            ftp.Method = System.Net.WebRequestMethods.Ftp.ListDirectory;
            //Give Message of Command
            NewMessageEventArgs e = new NewMessageEventArgs("COMMAND", "List Directory", "NLST");
            OnNewMessageReceived(this, e);

            string str = GetStringResponse(ftp);
            //replace CRLF to CR, remove last instance
            str = str.Replace("\r\n", "\r").TrimEnd('\r');
            //split the string into a list
            List<string> result = new List<string>();
            result.AddRange(str.Split('\r'));
            return result;
        }

        /// <summary>
        /// Return a detailed directory listing
        /// </summary>
        /// <param name="directory">Directory to list, e.g. /pub/etc</param>
        /// <returns>An FTPDirectory object</returns>
        public FTPdirectory ListDirectoryDetail(string directory)
        {
            System.Net.FtpWebRequest ftp = GetRequest(GetDirectory(directory));
            //Set request to do simple list
            ftp.Method = System.Net.WebRequestMethods.Ftp.ListDirectoryDetails;
            ftp.UseBinary = true;
            //Give Message of Command
            NewMessageEventArgs e = new NewMessageEventArgs("COMMAND", "List Directory Details", "LIST");
            OnNewMessageReceived(this, e);
            string str = GetStringResponse(ftp);
            //replace CRLF to CR, remove last instance
            str = str.Replace("\r\n", "\r").TrimEnd('\r');
            //split the string into a list
            return new FTPdirectory(str, _lastDirectory);
        }

        #endregion

        #region "Upload: File transfer TO ftp server"
        /// <summary>
        /// Copy a local file to the FTP server
        /// </summary>
        /// <param name="localFilename">Full path of the local file</param>
        /// <param name="targetFilename">Target filename, if required</param>
        /// <returns></returns>
        /// <remarks>If the target filename is blank, the source filename is used
        /// (assumes current directory). Otherwise use a filename to specify a name
        /// or a full path and filename if required.</remarks>
        public bool Upload(string localFilename, string targetFilename)
        {
            //1. check source
            if (!File.Exists(localFilename))
            {
                throw (new ApplicationException("File " + localFilename + " not found"));
            }
            //copy to FI
            FileInfo fi = new FileInfo(localFilename);
            return Upload(fi, targetFilename);
        }

        #region Upload Variables
        System.Net.FtpWebRequest UploadFTPRequest = null;
        FileStream UploadFileStream = null;
        Stream UploadStream = null;
        bool UploadCanceled = false;
        FileInfo UploadFileInfo = null;
        #endregion

        /// <summary>
        /// Upload a local file to the FTP server
        /// </summary>
        /// <param name="fi">Source file</param>
        /// <param name="targetFilename">Target filename (optional)</param>
        /// <returns></returns>
        public bool Upload(FileInfo fi, string targetFilename)
        {
            //copy the file specified to target file: target file can be full path or just filename (uses current dir)

            //1. check target
            string target;
            if (targetFilename.Trim() == "")
            {
                //Blank target: use source filename & current dir
                target = this.CurrentDirectory + fi.Name;
            }
            else if (targetFilename.Contains("/"))
            {
                //If contains / treat as a full path
                target = AdjustDir(targetFilename);
            }
            else
            {
                //otherwise treat as filename only, use current directory
                target = CurrentDirectory + targetFilename;
            }

            string URI = Hostname + target;
            //perform copy
            UploadFTPRequest = GetRequest(URI);

            //Set request to upload a file in binary
            UploadFTPRequest.Method = System.Net.WebRequestMethods.Ftp.UploadFile;
            UploadFTPRequest.UseBinary = true;
            //Notify FTP of the expected size
            UploadFTPRequest.ContentLength = fi.Length;
            UploadFileInfo = fi;

            //create byte array to store: ensure at least 1 byte!
            const int BufferSize = 2048;
            byte[] content = new byte[BufferSize - 1 + 1];
            int dataRead;

            //open file for reading
            using (UploadFileStream = fi.OpenRead())
            {
                try
                {
                    //open request to send
                    using (UploadStream = UploadFTPRequest.GetRequestStream())
                    {
                        //Give Message of Command
                        NewMessageEventArgs e = new NewMessageEventArgs("COMMAND", "Upload File", "STOR");
                        OnNewMessageReceived(this, e);

                        //Get File Size
                        Int64 TotalBytesUploaded = 0;
                        Int64 FileSize = fi.Length;
                        do
                        {
                            if (UploadCanceled)
                            {
                                NewMessageEventArgs CancelMessage = new NewMessageEventArgs("RESPONSE", "Upload Canceled.", "CANCEL");
                                OnNewMessageReceived(this, CancelMessage);
                                UploadCanceled = false;
                                return false;
                            }

                            dataRead = UploadFileStream.Read(content, 0, BufferSize);
                            UploadStream.Write(content, 0, dataRead);
                            TotalBytesUploaded += dataRead;
                            //Declare Event
                            UploadProgressChangedArgs DownloadProgress = new UploadProgressChangedArgs(TotalBytesUploaded, FileSize);

                            //Progress changed, Raise the event.
                            OnUploadProgressChanged(this, DownloadProgress);

                            System.Windows.Forms.Application.DoEvents();
                        } while (!(dataRead < BufferSize));

                        //Get Message and Raise Event
                        NewMessageEventArgs UPloadResponse = new NewMessageEventArgs("RESPONSE", "File Uploaded!", "STOR");
                        OnNewMessageReceived(this, UPloadResponse);

                        //Declare Event
                        UploadCompletedArgs Args = new UploadCompletedArgs("Successful", true);
                        //Raise Event
                        OnUploadCompleted(this, Args);

                        UploadStream.Close();
                    }

                }
                catch (Exception ex)
                {
                    //Declare Event
                    UploadCompletedArgs Args = new UploadCompletedArgs("Error: " + ex.Message, false);
                    //Raise Event
                    OnUploadCompleted(this, Args);
                }
                finally
                {
                    //ensure file closed
                    UploadFileStream.Close();
                }

            }


            UploadFTPRequest = null;
            return true;

        }

        public void CancelUpload(string UploadFileName)
        {
            if (UploadFileStream != null)
            {
                UploadFileStream.Close();
                UploadFTPRequest.Abort();
                //UploadFileInfo.Delete();
                UploadCanceled = true;
                UploadFTPRequest = null;
                this.FtpDelete(UploadFileName);
                MessageBox.Show("Upload Canceled");
            }
        }
        #endregion

        #region "Download: File transfer FROM ftp server"
        /// <summary>
        /// Copy a file from FTP server to local
        /// </summary>
        /// <param name="sourceFilename">Target filename, if required</param>
        /// <param name="localFilename">Full path of the local file</param>
        /// <returns></returns>
        /// <remarks>Target can be blank (use same filename), or just a filename
        /// (assumes current directory) or a full path and filename</remarks>
        public bool Download(string sourceFilename, string localFilename, bool PermitOverwrite)
        {
            //2. determine target file
            FileInfo fi = new FileInfo(localFilename);
            return this.Download(sourceFilename, fi, PermitOverwrite);
        }

        //Version taking an FtpFileInfo
        public bool Download(FTPfileInfo file, string localFilename, bool PermitOverwrite)
        {
            return this.Download(file.FullName, localFilename, PermitOverwrite);
        }

        //Another version taking FtpFileInfo and FileInfo
        public bool Download(FTPfileInfo file, FileInfo localFI, bool PermitOverwrite)
        {
            return this.Download(file.FullName, localFI, PermitOverwrite);
        }

        #region Download Variables
        System.Net.FtpWebRequest DownloadFTPRequest = null;
        FtpWebResponse DownloadResponse = null;
        Stream DownloadResponseStream = null;   //中文亂碼
        FileStream DownloadFileStream = null;
        FileInfo TargetFileInfo = null;
        bool DownloadCanceled = false;
        #endregion
        //Version taking string/FileInfo
        public bool Download(string sourceFilename, FileInfo targetFI, bool PermitOverwrite)
        {
            //1. check target
            if (targetFI.Exists && !(PermitOverwrite))
            {
                throw (new ApplicationException("Target file already exists"));
            }

            //2. check source
            string target;
            if (sourceFilename.Trim() == "")
            {
                throw (new ApplicationException("File not specified"));
            }
            else if (sourceFilename.Contains("/"))
            {
                //treat as a full path
                target = AdjustDir(sourceFilename);
            }
            else
            {
                //treat as filename only, use current directory
                target = CurrentDirectory + sourceFilename;
            }

            string URI = Hostname + target;

            //3. perform copy
            DownloadFTPRequest = GetRequest(URI);

            //Set request to download a file in binary mode
            DownloadFTPRequest.Method = System.Net.WebRequestMethods.Ftp.DownloadFile;
            DownloadFTPRequest.UseBinary = true;
            TargetFileInfo = targetFI;
            //open request and get response stream
            using (DownloadResponse = (FtpWebResponse)DownloadFTPRequest.GetResponse())
            {
                using (DownloadResponseStream = DownloadResponse.GetResponseStream())
                {
                    //System.Security.AccessControl.FileSecurity fileSecurity = new System.Security.AccessControl.FileSecurity(targetFI.FullName, System.Security.AccessControl.AccessControlSections.All);
                    //targetFI.SetAccessControl(fileSecurity);
                    //loop to read & write to file
                    using (DownloadFileStream = new FileStream(targetFI.FullName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
                    {
                        try
                        {
                            //Give Message of Command
                            NewMessageEventArgs e = new NewMessageEventArgs("COMMAND", "Download File", "RETR");
                            OnNewMessageReceived(this, e);
                            byte[] buffer = new byte[2048];
                            int read = 0;
                            Int64 TotalBytesRead = 0;
                            Int64 FileSize = this.GetFileSize(sourceFilename);
                            DownloadCanceled = false;
                            do
                            {
                                if (DownloadCanceled)
                                {
                                    NewMessageEventArgs CancelMessage = new NewMessageEventArgs("RESPONSE", "Download Canceled.", "CANCEL");

                                    DownloadCanceled = false;
                                    OnNewMessageReceived(this, CancelMessage);
                                    return false;
                                }

                                read = DownloadResponseStream.Read(buffer, 0, buffer.Length);
                                DownloadFileStream.Write(buffer, 0, read);
                                TotalBytesRead += read;
                                //Declare Event
                                DownloadProgressChangedArgs DownloadProgress = new DownloadProgressChangedArgs(TotalBytesRead, FileSize);

                                //Progress changed, Raise the event.
                                OnDownloadProgressChanged(this, DownloadProgress);

                                System.Windows.Forms.Application.DoEvents();

                            } while (!(read == 0));


                            //Get Message and Raise Event
                            NewMessageEventArgs NewMessageArgs = new NewMessageEventArgs("RESPONSE", DownloadResponse.StatusDescription, DownloadResponse.StatusCode.ToString());
                            OnNewMessageReceived(this, NewMessageArgs);

                            //Declare Event
                            DownloadCompletedArgs Args = new DownloadCompletedArgs("Successful", true);
                            //Raise Event
                            OnDownloadCompleted(this, Args);

                            DownloadResponseStream.Close();
                            DownloadFileStream.Flush();
                            DownloadFileStream.Close();
                            DownloadFileStream = null;
                            DownloadResponseStream = null;
                        }
                        catch (Exception ex)
                        {
                            //catch error and delete file only partially downloaded
                            DownloadFileStream.Close();
                            //delete target file as it's incomplete
                            targetFI.Delete();

                            //Decalre Event for Error
                            DownloadCompletedArgs DownloadCompleted = new DownloadCompletedArgs("Error: " + ex.Message, false);
                            //Raise Event
                            OnDownloadCompleted(this, DownloadCompleted);
                        }
                    }
                    if (DownloadFileStream != null)
                        DownloadResponseStream.Close();
                }
                if (DownloadFileStream != null)
                    DownloadResponse.Close();
            }
            return true;
        }

        public void CancelDownload()
        {
            if (DownloadFileStream != null)
            {
                DownloadFileStream.Close();

                DownloadFTPRequest.Abort();

                DownloadResponse.Close();
                DownloadResponseStream.Close();
                //DownloadFileStream = null;
                //DownloadResponseStream = null;
                TargetFileInfo.Delete();
                DownloadCanceled = true;
                MessageBox.Show("Download Canceled");
            }
        }
        #endregion

        #region "Other functions: Delete rename etc."
        /// <summary>
        /// Delete remote file
        /// </summary>
        /// <param name="filename">filename or full path</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public bool FtpDelete(string filename)
        {
            //Determine if file or full path
            string URI = this.Hostname + GetFullPath(filename);

            System.Net.FtpWebRequest ftp = GetRequest(URI);
            //Set request to delete
            ftp.Method = System.Net.WebRequestMethods.Ftp.DeleteFile;
            try
            {
                //get response but ignore it
                string str = GetStringResponse(ftp);
                //Give Message of Command
                NewMessageEventArgs e = new NewMessageEventArgs("COMMAND", "Delete File", "DELE");
                OnNewMessageReceived(this, e);
            }
            catch (Exception)
            {
                return false;
            }
            return true;
        }

        /// <summary>
        /// Determine if file exists on remote FTP site
        /// </summary>
        /// <param name="filename">Filename (for current dir) or full path</param>
        /// <returns></returns>
        /// <remarks>Note this only works for files</remarks>
        public bool FtpFileExists(string filename)
        {
            //Try to obtain filesize: if we get error msg containing "550"
            //the file does not exist
            try
            {
                long size = GetFileSize(filename);
                return true;

            }
            catch (Exception ex)
            {
                //only handle expected not-found exception
                if (ex is System.Net.WebException)
                {
                    //file does not exist/no rights error = 550
                    if (ex.Message.Contains("550"))
                    {
                        //clear
                        return false;
                    }
                    else
                    {
                        System.Windows.Forms.MessageBox.Show(ex.Message);
                        return false;
                    }
                }
                else
                {
                    System.Windows.Forms.MessageBox.Show(ex.Message);
                    return false;
                }
            }
        }

        /// <summary>
        /// Determine size of remote file
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        /// <remarks>Throws an exception if file does not exist</remarks>
        public long GetFileSize(string filename)
        {
            string path;
            if (filename.Contains("/"))
            {
                path = AdjustDir(filename);
            }
            else
            {
                path = this.CurrentDirectory + filename;
            }
            string URI = this.Hostname + path;
            System.Net.FtpWebRequest ftp = GetRequest(URI);
            //Try to get info on file/dir?
            ftp.Method = System.Net.WebRequestMethods.Ftp.GetFileSize;
            string tmp = this.GetStringResponse(ftp);
            //Give Message of Command
            NewMessageEventArgs e = new NewMessageEventArgs("COMMAND", "Get File Size", "SIZE");
            OnNewMessageReceived(this, e);
            return GetSize(ftp);
        }

        public bool FtpRename(string sourceFilename, string newName)
        {
            //Does file exist?
            string source = GetFullPath(sourceFilename);
            if (!FtpFileExists(source))
            {
                throw (new FileNotFoundException("File " + source + " not found"));
            }

            //build target name, ensure it does not exist
            string target = GetFullPath(newName);
            if (target == source)
            {
                throw (new ApplicationException("Source and target are the same"));
            }
            else if (FtpFileExists(target))
            {
                throw (new ApplicationException("Target file " + target + " already exists"));
            }

            //perform rename
            string URI = this.Hostname + source;

            System.Net.FtpWebRequest ftp = GetRequest(URI);
            //Set request to delete
            ftp.Method = System.Net.WebRequestMethods.Ftp.Rename;
            ftp.RenameTo = target;
            ftp.UseBinary = true;

            try
            {
                //get response but ignore it
                string str = GetStringResponse(ftp);
                //Give Message of Command
                NewMessageEventArgs e = new NewMessageEventArgs("COMMAND", "File Rename", "RENAME");
                OnNewMessageReceived(this, e);
            }
            catch (Exception)
            {
                return false;
            }
            return true;
        }

        public bool FtpCreateDirectory(string dirpath)
        {
            //perform create
            string URI = this.Hostname + AdjustDir(dirpath);
            System.Net.FtpWebRequest ftp = GetRequest(URI);
            //Set request to MkDir
            ftp.Method = System.Net.WebRequestMethods.Ftp.MakeDirectory;
            try
            {
                //get response but ignore it
                string str = GetStringResponse(ftp);
                //Give Message of Command
                NewMessageEventArgs e = new NewMessageEventArgs("COMMAND", "Make Directory", "MKD");
                OnNewMessageReceived(this, e);
            }
            catch (Exception)
            {
                return false;
            }
            return true;
        }

        public bool FtpDeleteDirectory(string dirpath)
        {
            //perform remove
            string URI = this.Hostname + AdjustDir(dirpath);
            System.Net.FtpWebRequest ftp = GetRequest(URI);
            ftp.UseBinary = true;
            //Set request to RmDir
            ftp.Method = System.Net.WebRequestMethods.Ftp.RemoveDirectory;
            try
            {
                //get response but ignore it
                string str = GetStringResponse(ftp);
                //Give Message of Command
                NewMessageEventArgs e = new NewMessageEventArgs("COMMAND", "Remove Directory", "RMD");
                OnNewMessageReceived(this, e);
            }
            catch (Exception)
            {
                return false;
            }
            return true;
        }
        #endregion

        #region "private supporting fns"
        //Get the basic FtpWebRequest object with the
        //common settings and security
        private FtpWebRequest GetRequest(string URI)
        {
            //create request
            FtpWebRequest result = (FtpWebRequest)FtpWebRequest.Create(URI);
            //Set the login details
            result.Credentials = GetCredentials();
            //Do not keep alive (stateless mode)
            result.KeepAlive = false;
            result.UseBinary = true;
            return result;
        }


        /// <summary>
        /// Get the credentials from username/password
        /// </summary>
        private System.Net.ICredentials GetCredentials()
        {
            return new System.Net.NetworkCredential(Username, Password);
        }

        /// <summary>
        /// returns a full path using CurrentDirectory for a relative file reference
        /// </summary>
        private string GetFullPath(string file)
        {
            if (file.Contains("/"))
            {
                return AdjustDir(file);
            }
            else
            {
                return this.CurrentDirectory + file;
            }
        }

        /// <summary>
        /// Amend an FTP path so that it always starts with /
        /// </summary>
        /// <param name="path">Path to adjust</param>
        /// <returns></returns>
        /// <remarks></remarks>
        private string AdjustDir(string path)
        {
            return ((path.StartsWith("/")) ? "" : "/").ToString() + path;
        }

        private string GetDirectory(string directory)
        {
            string URI;
            if (directory == "")
            {
                //build from current
                URI = Hostname + this.CurrentDirectory;
                _lastDirectory = this.CurrentDirectory;
            }
            else
            {
                if (!directory.StartsWith("/"))
                {
                    throw (new ApplicationException("Directory should start with /"));
                }
                URI = this.Hostname + directory;
                _lastDirectory = directory;
            }
            return URI;
        }

        //stores last retrieved/set directory
        private string _lastDirectory = "";

        /// <summary>
        /// Obtains a response stream as a string
        /// </summary>
        /// <param name="ftp">current FTP request</param>
        /// <returns>String containing response</returns>
        /// <remarks>FTP servers typically return strings with CR and
        /// not CRLF. Use respons.Replace(vbCR, vbCRLF) to convert
        /// to an MSDOS string</remarks>
        private string GetStringResponse(FtpWebRequest ftp)
        {
            //Get the result, streaming to a string
            string result = "";
            using (FtpWebResponse response = (FtpWebResponse)ftp.GetResponse())
            {
                long size = response.ContentLength;
                using (Stream datastream = response.GetResponseStream())
                {
                    // 一中文亂碼問題 塗聚文 20180801
                    using (StreamReader sr = new StreamReader(datastream, System.Text.Encoding.GetEncoding("GB2312"))) 
                    {
                        _WelcomeMessage = response.WelcomeMessage;
                        _ExitMessage = response.ExitMessage;
                        result = sr.ReadToEnd();
                        sr.Close();
                    }
                    try
                    {
                        //Declare Event
                        NewMessageEventArgs e = new NewMessageEventArgs("RESPONSE", response.StatusDescription, response.StatusCode.ToString());
                        //Raise Event
                        OnNewMessageReceived(this, e);
                    }
                    catch
                    {

                    }

                    datastream.Close();
                }
                response.Close();
            }
            return result;
        }

        /// <summary>
        /// Gets the size of an FTP request
        /// </summary>
        /// <param name="ftp"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        private long GetSize(FtpWebRequest ftp)
        {
            long size;
            using (FtpWebResponse response = (FtpWebResponse)ftp.GetResponse())
            {
                size = response.ContentLength;
                response.Close();
            }

            return size;
        }
        #endregion

        #region "Properties"
        private string _hostname;
        /// <summary>
        /// Hostname
        /// </summary>
        /// <value></value>
        /// <remarks>Hostname can be in either the full URL format
        /// ftp://ftp.myhost.com or just ftp.myhost.com
        /// </remarks>
        public string Hostname
        {
            get
            {
                if (_hostname.StartsWith("ftp://"))
                {
                    return _hostname;
                }
                else
                {
                    return "ftp://" + _hostname;
                }
            }
            set
            {
                _hostname = value;
            }
        }
        private string _username;
        /// <summary>
        /// Username property
        /// </summary>
        /// <value></value>
        /// <remarks>Can be left blank, in which case 'anonymous' is returned</remarks>
        public string Username
        {
            get
            {
                return (_username == "" ? "anonymous" : _username);
            }
            set
            {
                _username = value;
            }
        }
        private string _password;
        public string Password
        {
            get
            {
                return _password;
            }
            set
            {
                _password = value;
            }
        }

        /// <summary>
        /// The CurrentDirectory value
        /// </summary>
        /// <remarks>Defaults to the root '/'</remarks>
        private string _currentDirectory = "/";
        public string CurrentDirectory
        {
            get
            {
                //return directory, ensure it ends with /
                return _currentDirectory + ((_currentDirectory.EndsWith("/")) ? "" : "/").ToString();
            }
            set
            {
                if (!value.StartsWith("/"))
                {
                    throw (new ApplicationException("Directory should start with /"));
                }
                _currentDirectory = value;
            }
        }


        #endregion

        #region Server Messages
        string _WelcomeMessage, _ExitMessage;
        public string WelcomeMessage
        {
            get
            {
                return _WelcomeMessage;
            }
            set
            {
                _WelcomeMessage = value;
            }
        }
        public string ExitMessage
        {
            get
            {
                return _ExitMessage;
            }
            set
            {
                _ExitMessage = value;
            }
        }
        #endregion

    }
    #endregion

    #region "FTP file info class"
    /// <summary>
    /// Represents a file or directory entry from an FTP listing
    /// </summary>
    /// <remarks>
    /// This class is used to parse the results from a detailed
    /// directory list from FTP. It supports most formats of
    /// </remarks>
    public class FTPfileInfo
    {

        //Stores extended info about FTP file

        #region "Properties"
        public string FullName
        {
            get
            {
                return Path + Filename;
            }
        }
        public string Filename
        {
            get
            {
                return _filename;
            }
        }
        public string Path
        {
            get
            {
                return _path;
            }
        }
        public DirectoryEntryTypes FileType
        {
            get
            {
                return _fileType;
            }
        }
        public long Size
        {
            get
            {
                return _size;
            }
        }
        public DateTime FileDateTime
        {
            get
            {
                return _fileDateTime;
            }
        }
        public string Permission
        {
            get
            {
                return _permission;
            }
        }
        public string Extension
        {
            get
            {
                int i = this.Filename.LastIndexOf(".");
                if (i >= 0 && i < (this.Filename.Length - 1))
                {
                    return this.Filename.Substring(i + 1);
                }
                else
                {
                    return "";
                }
            }
        }
        public string NameOnly
        {
            get
            {
                int i = this.Filename.LastIndexOf(".");
                if (i > 0)
                {
                    return this.Filename.Substring(0, i);
                }
                else
                {
                    return this.Filename;
                }
            }
        }
        private string _filename;
        private string _path;
        private DirectoryEntryTypes _fileType;
        private long _size;
        private DateTime _fileDateTime;
        private string _permission;

        #endregion

        /// <summary>
        /// Identifies entry as either File or Directory
        /// </summary>
        public enum DirectoryEntryTypes
        {
            File,
            Directory
        }

        /// <summary>
        /// Constructor taking a directory listing line and path
        /// </summary>
        /// <param name="line">The line returned from the detailed directory list</param>
        /// <param name="path">Path of the directory</param>
        /// <remarks></remarks>
        public FTPfileInfo(string line, string path)
        {
            //parse line
            Match m = GetMatchingRegex(line);
            if (m == null)
            {
                //failed
                throw (new ApplicationException("Unable to parse line: " + line));
            }
            else
            {
                _filename = m.Groups["name"].Value;
                _path = path;

                Int64.TryParse(m.Groups["size"].Value, out _size);
                //_size = System.Convert.ToInt32(m.Groups["size"].Value);

                _permission = m.Groups["permission"].Value;
                string _dir = m.Groups["dir"].Value;
                if (_dir != "" && _dir != "-")
                {
                    _fileType = DirectoryEntryTypes.Directory;
                }
                else
                {
                    _fileType = DirectoryEntryTypes.File;
                }

                try
                {
                    _fileDateTime = DateTime.Parse(m.Groups["timestamp"].Value);
                }
                catch (Exception)
                {
                    _fileDateTime = Convert.ToDateTime(null);
                }

            }
        }

        private Match GetMatchingRegex(string line)
        {
            Regex rx;
            Match m;
            for (int i = 0; i <= _ParseFormats.Length - 1; i++)
            {
                rx = new Regex(_ParseFormats[i]);
                m = rx.Match(line);
                if (m.Success)
                {
                    return m;
                }
            }
            return null;
        }

        #region "Regular expressions for parsing LIST results"
        /// <summary>
        /// List of REGEX formats for different FTP server listing formats
        /// </summary>
        /// <remarks>
        /// The first three are various UNIX/LINUX formats, fourth is for MS FTP
        /// in detailed mode and the last for MS FTP in 'DOS' mode.
        /// I wish VB.NET had support for Const arrays like C# but there you go
        /// </remarks>
        private static string[] _ParseFormats = new string[] { 
            "(?<dir>[\\-d])(?<permission>([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\w+\\s+\\w+\\s+(?<size>\\d+)\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{4})\\s+(?<name>.+)", 
            "(?<dir>[\\-d])(?<permission>([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\d+\\s+(?<size>\\d+)\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{4})\\s+(?<name>.+)", 
            "(?<dir>[\\-d])(?<permission>([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\d+\\s+(?<size>\\d+)\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{1,2}:\\d{2})\\s+(?<name>.+)", 
            "(?<dir>[\\-d])(?<permission>([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\w+\\s+\\w+\\s+(?<size>\\d+)\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{1,2}:\\d{2})\\s+(?<name>.+)", 
            "(?<dir>[\\-d])(?<permission>([\\-r][\\-w][\\-xs]){3})(\\s+)(?<size>(\\d+))(\\s+)(?<ctbit>(\\w+\\s\\w+))(\\s+)(?<size2>(\\d+))\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{2}:\\d{2})\\s+(?<name>.+)", 
            "(?<timestamp>\\d{2}\\-\\d{2}\\-\\d{2}\\s+\\d{2}:\\d{2}[Aa|Pp][mM])\\s+(?<dir>\\<\\w+\\>){0,1}(?<size>\\d+){0,1}\\s+(?<name>.+)" };
        #endregion
    }
    #endregion

    #region "FTP Directory class"
    /// <summary>
    /// Stores a list of files and directories from an FTP result
    /// </summary>
    /// <remarks></remarks>
    public class FTPdirectory : List<FTPfileInfo>
    {


        public FTPdirectory()
        {
            //creates a blank directory listing
        }

        /// <summary>
        /// Constructor: create list from a (detailed) directory string
        /// </summary>
        /// <param name="dir">directory listing string</param>
        /// <param name="path"></param>
        /// <remarks></remarks>
        public FTPdirectory(string dir, string path)
        {
            foreach (string line in dir.Replace("\n", "").Split(System.Convert.ToChar('\r')))
            {
                //parse
                if (line != "")
                {
                    this.Add(new FTPfileInfo(line, path));
                }
            }
        }

        /// <summary>
        /// Filter out only files from directory listing
        /// </summary>
        /// <param name="ext">optional file extension filter</param>
        /// <returns>FTPdirectory listing</returns>
        public FTPdirectory GetFiles(string ext)
        {
            return this.GetFileOrDir(FTPfileInfo.DirectoryEntryTypes.File, ext);
        }

        /// <summary>
        /// Returns a list of only subdirectories
        /// </summary>
        /// <returns>FTPDirectory list</returns>
        /// <remarks></remarks>
        public FTPdirectory GetDirectories()
        {
            return this.GetFileOrDir(FTPfileInfo.DirectoryEntryTypes.Directory, "");
        }

        //internal: share use function for GetDirectories/Files
        private FTPdirectory GetFileOrDir(FTPfileInfo.DirectoryEntryTypes type, string ext)
        {
            FTPdirectory result = new FTPdirectory();
            foreach (FTPfileInfo fi in this)
            {
                if (fi.FileType == type)
                {
                    if (ext == "")
                    {
                        result.Add(fi);
                    }
                    else if (ext == fi.Extension)
                    {
                        result.Add(fi);
                    }
                }
            }
            return result;

        }

        public bool FileExists(string filename)
        {
            foreach (FTPfileInfo ftpfile in this)
            {
                if (ftpfile.Filename == filename)
                {
                    return true;
                }
            }
            return false;
        }

        private const char slash = '/';

        public static string GetParentDirectory(string dir)
        {
            string tmp = dir.TrimEnd(slash);
            int i = tmp.LastIndexOf(slash);
            if (i > 0)
            {
                return tmp.Substring(0, i - 1);
            }
            else
            {
                throw (new ApplicationException("No parent for root"));
            }
        }
    }
    #endregion

    #region Events
    public class DownloadProgressChangedArgs : EventArgs
    {
        //Private Members
        private Int64 _BytesDownload;
        private Int64 _TotalBytes;

        //Constructor
        public DownloadProgressChangedArgs(Int64 BytesDownload, Int64 TotleBytes)
        {
            this._BytesDownload = BytesDownload;
            this._TotalBytes = TotleBytes;
        }

        //Public Members
        public Int64 BytesDownloaded { get { return _BytesDownload; } }
        public Int64 TotleBytes { get { return _TotalBytes; } }
    }

    public class DownloadCompletedArgs : EventArgs
    {
        //Private Members
        private bool _DownloadedCompleted;
        private string _DownloadStatus;

        //Constructor
        public DownloadCompletedArgs(string Status, bool Completed)
        {
            this._DownloadedCompleted = Completed;
            this._DownloadStatus = Status;
        }

        //Public Members
        public String DownloadStatus { get { return _DownloadStatus; } }
        public bool DownloadCompleted { get { return _DownloadedCompleted; } }
    }

    public class NewMessageEventArgs : EventArgs
    {
        //Private Members
        private string _Message;
        private string _StatusCode;
        private string _Type;

        //Constructor
        public NewMessageEventArgs(string Type, string Status, string Code)
        {
            this._Message = Status;
            this._StatusCode = Code;
            this._Type = Type;
        }

        //Public Members
        public string StatusMessage { get { return _Message; } }
        public string StatusCode { get { return _StatusCode; } }
        public string StatusType { get { return _Type; } }
    }

    public class UploadProgressChangedArgs : EventArgs
    {
        //Private Members
        private Int64 _BytesUpload;
        private Int64 _TotalBytes;

        //Constructor
        public UploadProgressChangedArgs(Int64 BytesUpload, Int64 TotleBytes)
        {
            this._BytesUpload = BytesUpload;
            this._TotalBytes = TotleBytes;
        }

        //Public Members
        public Int64 BytesUploaded { get { return _BytesUpload; } }
        public Int64 TotleBytes { get { return _TotalBytes; } }
    }

    public class UploadCompletedArgs : EventArgs
    {
        //Private Members
        private bool _UploadCompleted;
        private string _UploadStatus;

        //Constructor
        public UploadCompletedArgs(string Status, bool Completed)
        {
            this._UploadCompleted = Completed;
            this._UploadStatus = Status;
        }

        //Public Members
        public String UploadStatus { get { return _UploadStatus; } }
        public bool UploadCompleted { get { return _UploadCompleted; } }
    }
    #endregion
}

  測試代碼:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using FTPLibrary;
using System.Diagnostics;
using System.Reflection;
using System.IO;


namespace ftpdemo
{

    /// <summary>
    /// 塗聚文 2017-08-01
    /// </summary>
    public partial class Form6 : Form
    {
        public FTPclient FtpClient;
        ListViewItem Message;
        string remotingFolder = System.Configuration.ConfigurationManager.AppSettings["remotingFolder"];  //遠程ftp文件目錄
        string localFolder = System.Configuration.ConfigurationManager.AppSettings["localFolder"];  //要下載到的本地目錄
        string ftpServer = System.Configuration.ConfigurationManager.AppSettings["ftpServer"];  //ftp伺服器
        string user = System.Configuration.ConfigurationManager.AppSettings["user"];  //用戶名
        string pwd = System.Configuration.ConfigurationManager.AppSettings["pwd"];  //密碼
        string port = System.Configuration.ConfigurationManager.AppSettings["port"];  //埠

        /// <summary>
        /// 
        /// </summary>
        /// <param name="byteCount"></param>
        /// <returns></returns>
        private string GetFileSize(double byteCount)
        {
            string size = "0 Bytes";
            if (byteCount >= 1073741824.0)
                size = String.Format("{0:##.##}", byteCount / 1073741824.0) + " GB";
            else if (byteCount >= 1048576.0)
                size = String.Format("{0:##.##}", byteCount / 1048576.0) + " MB";
            else if (byteCount >= 1024.0)
                size = String.Format("{0:##.##}", byteCount / 1024.0) + " KB";
            else if (byteCount > 0 && byteCount < 1024.0)
                size = byteCount.ToString() + " Bytes";

            return size;
        }
        /// <summary>
        /// Sets up the FTPClient for this Form.  Called from frmLogin.
        /// </summary>
        /// <param name="client">FTPclient on frmLogin is used to refrence the FtpClient here.</param>
        public void SetFtpClient(FTPclient client)
        {
            //Set FtpClient
            FtpClient = client;

            //Display the Welcome Message
            Message = new ListViewItem();
            Message.Text = DateTime.Now.ToLongTimeString() + " " + DateTime.Now.ToLongDateString();
            Message.SubItems.Add("Welcome Message");
            Message.SubItems.Add(FtpClient.WelcomeMessage);
            Message.SubItems.Add("No Code");
            Message.SubItems.Add("/");
            lstMessages.Items.Add(Message);

            //Setup OnMessageReceived Event
            FtpClient.OnNewMessageReceived += new FTPclient.NewMessageHandler(FtpClient_OnNewMessageReceived);

            //Open and Display Root Directory and Files/Folders in it
            foreach (FTPfileInfo folder in FtpClient.ListDirectoryDetail("/"))
            {
                ListViewItem item = new ListViewItem();
                item.Text = folder.Filename;
                if (folder.FileType == FTPfileInfo.DirectoryEntryTypes.Directory)
                    item.SubItems.Add("Folder");
                else
                    item.SubItems.Add("File");

                item.SubItems.Add(folder.FullName);
                item.SubItems.Add(folder.Permission);
                item.SubItems.Add(folder.FileDateTime.ToShortTimeString() + folder.FileDateTime.ToShortDateString());
                item.SubItems.Add(GetFileSize(folder.Size));
                lstRemoteSiteFiles.Items.Add(item);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="myObject"></param>
        /// <param name="e"></param>
        private void FtpClient_OnNewMessageReceived(object myObject, NewMessageEventArgs e)
        {
            //Display Meesage in lstMessages
            Message = new ListViewItem();
            Message.Text = DateTime.Now.ToLongTimeString() + " " + DateTime.Now.ToLongDateString();
            Message.SubItems.Add(e.StatusType);
            Message.SubItems.Add(e.StatusMessage);
            Message.SubItems.Add(e.StatusCode);
            Message.SubItems.Add(txtRemoteDirectory.Text);
            lstMessages.Items.Add(Message);

            this.lstMessages.EnsureVisible(this.lstMessages.Items.Count - 1);
        }
        /// <summary>
        /// Reload all Directories and Files in Current Directory
        /// </summary>
        private void RefreshDirectory()
        {
            //Clear all items
            lstRemoteSiteFiles.Items.Clear();

            //Open and Display Root Directory
            foreach (FTPfileInfo folder in FtpClient.ListDirectoryDetail(txtRemoteDirectory.Text))
            {
                ListViewItem item = new ListViewItem();
                item.Text = folder.Filename;
                if (folder.FileType == FTPfileInfo.DirectoryEntryTypes.Directory)
                    item.SubItems.Add("Folder");
                else
                    item.SubItems.Add("File");

                item.SubItems.Add(folder.FullName);
                item.SubItems.Add(folder.Permission);
                item.SubItems.Add(folder.FileDateTime.ToShortTimeString() + folder.FileDateTime.ToShortDateString());
                item.SubItems.Add(folder.Size.ToString());
                lstRemoteSiteFiles.Items.Add(item);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public Form6()
        {
            InitializeComponent();

            //Set Selected Directory
            txtRemoteDirectory.Text = "/";
            lstRemoteSiteFiles.FullRowSelect = true;  
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form6_Load(object sender, EventArgs e)
        {
            //Set FTP
            FTPclient objFtp = new FTPclient(ftpServer, user,pwd);
            objFtp.CurrentDirectory = "/";
            SetFtpClient(objFtp);

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lstRemoteSiteFiles_SelectedIndexChanged(object sender, EventArgs e)
        {

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lstRemoteSiteFiles_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (lstRemoteSiteFiles.Items.Count != 0)
            {
                try
                {
                    if (lstRemoteSiteFiles.SelectedItems[0].SubItems[1].Text == "File")
                    {
                        //Enable the buttons that are related to the FILE
                       // btnRename.Enabled = true;
                       // btnDownload.Enabled = true;
                        //Set Current Directory for Download
                        FtpClient.CurrentDirectory = txtRemoteDirectory.Text;
                        //Its a File, so Ask them if they want to Save it...
                        if (MessageBox.Show("Do you want to save this file: " + txtRemoteDirectory.Text + lstRemoteSiteFiles.SelectedItems[0].Text + "/" + "?", "Download File?", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) == DialogResult.Yes)
                        {
                            //Save the File to location
                            //downloadToolStripMenuItem_Click(this, e);
                        }
                    }
                    else if (lstRemoteSiteFiles.SelectedItems[0].SubItems[1].Text == "Folder") // Its a Directory
                    {
                        //Set Directory to txtRemoteDirectory.Text + selectedItem + "/"
                        //Result - /SelectedDirecotory/  -- good for navigation, keeping user informed and code :)
                        txtRemoteDirectory.Text += lstRemoteSiteFiles.SelectedItems[0].Text + "/";
                        lstRemoteSiteFiles.Items.Clear();

                        //Set Current Dir
                        FtpClient.CurrentDirectory = txtRemoteDirectory.Text;

                        //Get Files and Folders from Selected Direcotry
                        foreach (FTPfileInfo folder in FtpClient.ListDirectoryDetail(txtRemoteDirectory.Text))
                        {
                            ListViewItem item = new ListViewItem();
                            item.Text = folder.Filename;
                            if (folder.FileType == FTPfileInfo.DirectoryEntryTypes.Directory)
                                item.SubItems.Add("Folder");
                            else
                                item.SubItems.Add("File");

                            item.SubItems.Add(folder.FullName);
                            item.SubItems.Add(folder.Permission);
                            item.SubItems.Add(folder.FileDateTime.ToShortDateString()+" "+folder.FileDateTime.ToShortTimeString());
                            item.SubItems.Add(GetFileSize(folder.Size));
                            lstRemoteSiteFiles.Items.Add(item);
                        }
                    }
                }
                catch { }
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lstRemoteSiteFiles_ItemDrag(object sender, ItemDragEventArgs e)
        {

        }
    }
}

  


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.keras模型可視化 keras.utils.vis_utils模塊提供了畫出Keras模型的函數(利用graphviz) 該函數將畫出模型結構圖,並保存成圖片: plot_model接收兩個可選參數: show_shapes:指定是否顯示輸出數據的形狀,預設為False show_layer_ ...
  • 一、前言: ssh遠程登錄密碼認證的方式有三種,password、Keyboard Interactive、Public Key 前面兩種方式就是密碼認證,含義都是一樣大同小異。第三種是登錄方式最安全的一種。 下麵我們就來實現第三種方式public key秘鑰認證方式。 二、原理: ssh客戶端利用 ...
  • 1、與用戶(user)和用戶組(group)相關的配置文件; 1)與用戶(user)相關的配置文件;/etc/passwd 註:用戶(user)的配置文件;/etc/shadow 註:用戶(user)影子口令文件; 2)與用戶組(group)相關的配置文件;/etc/group 註:用戶組(grou ...
  • 幾天前,我和我的朋友們使用 ASP.NET Core 開發了一個API ,使用的是GET方式,將一些數據返回到客戶端 APP。我們在前端進行了分頁,意味著我們將所有數據發送給客戶端,然後進行一些data.length操作,以獲得items count用於分頁邏輯。為了減少HTTP請求的負荷,我們決定 ...
  • 首先,添加一個類AuthenticationAttribute,該類繼承AuthorizeAttribute,如下: using System.Web; using System.Web.Mvc; namespace Zhong.Web { public class AuthenticationAt ...
  • 效果 實現思路 使用TcpListener建一個伺服器,接收所有客戶端發送的消息,然後由伺服器再發送到其他客戶端 客戶端使用TcpClient,發消息給伺服器,接收伺服器的消息,不和其他客戶端直接交互 伺服器端 開啟一個線程,死迴圈去接收客戶端.接收到之後放到一個集合里,保存起來,以便轉發消息用.每 ...
  • 上文簡單介紹了一下Entity FrameWork,這裡說一下EF的核心——edmx文件。 在VisualStudio中建立edmx文件(此例環境為VisualStudio2012) 1、新建—ADO.NET實體數據模型: 2、選擇數據模型時,因為我之前已經在資料庫中建立好表了,所以我們這裡先選擇從 ...
  • Entity Framework是以ADO.NET為基礎,面向數據的“實體框架”。以下簡稱EF。 它利用了抽象化數據結構的方式,將每個資料庫對象都轉換成應用程式對象 (entity),數據欄位都轉換為屬性 (property),關係則轉換為結合屬性 (association),讓資料庫的 E/R 模 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...