关于如何实现FTP上传或者下载带进度和速率的实现方法

关于如何实现FTP上传或者下载带进度和速率的实现方法,第1张

在这里需要说明的是,该方式是通过其他代码进行改进的。 首先我们需要定义一个委托,用来实现传输过程中传递文件的总数,已完成的字节数和速度,方便客户端界面上调用。 public delegate void TransferProcess(long total,long finished,double speed)调用代码就不举例了 接下来我们建立一个FTPClient类,该类基于socket和FTP协议实现了连接FTP服务,建立目录,上传文件,下载文件等主要方法。结构如下: 需要注意的是,我们需要定一个事件event TransferProcess OnTransferProcess该事件在实例化FTPClient之后需要调用,这个事件对实现进度条和速率是非常重要的。为了实现速率我们还需要定义个公开的成员startTime(开始时间)。我们现在主要是看一下如何上传的。 /// /// 上传一个文件 /// /// 本地文件名 public void Put(string strFileName) { //连接服务器 if (!bConnected) { Connect()} UpdateStatus = true//建立socket连接 Socket socketData = CreateDataSocket()//向FTP服务器发生存储命令 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 = 0long total = input.Length//该成员主要记录文件的总字节数,注意这里使用长整型,是为了突破只能传输2G左右的文件的限制 long finished = 0//该成员主要记录已经传输完成的字节数,注意这里使用长整型,是为了突破只能传输2G左右的文件的限制 double speed = 0//记录传输的速率 while ((iBytes = input.Read(buffer, 0, buffer.Length)) >0)//循环从本地数据流中读取数据到缓冲区 { //Console.WriteLine(startTime.ToString())socketData.Send(buffer, iBytes, 0)//将缓冲区的数据发送到FTP服务器 DateTime endTime = DateTime.Now//每次发送数据的结束时间 TimeSpan ts = endTime - startTime//计算每次发送数据的时间间隔 finished += iBytes//计算完成的字节数. Console.WriteLine(ts.Milliseconds)//计算速率,注意finished是字节,所以需要换算冲K字节 if (ts.Milliseconds >0) { speed = (double)(finished / ts.TotalMilliseconds)speed = Math.Round(speed * 1000 / 1024, 2)} //这里是必不可少的,否则你无法实现进度条 //如果传输进度事件被实例化,而且从本地数据流中读取数据不是空的并完成的字节数也不为空的话,则实现委托. if (OnTransferProcess != null&&iBytes>0&&finished>0) { OnTransferProcess(total, finished,speed)} } UpdateStatus = falsefinished = 0input.Close()//当传输完成之后需要关闭数据流,以便下次访问. if (socketData.Connected) { socketData.Close()//关闭当前的socket } if (!(iReplyCode == 226 || iReplyCode == 250)) { ReadReply()if (!(iReplyCode == 226 || iReplyCode == 250)) { UpdateStatus = falsethrow new IOException(strReply.Substring(4))} } } 上面代码中注释写得比较详细,这里就不再一一讲解了,关于下载中实现进度条和速率的问题可以参考以上代码进行修改. 完整的代码如下: using Systemusing System.netusing System.IOusing System.Textusing System.net.Socketsnamespace MMSEncoder { public delegate void TransferProcess(long total,long finished,double speed)/// /// FTP Client /// public class FTPClient { public event TransferProcess OnTransferProcesspublic bool UpdateStatus = truepublic DateTime startTimeprivate bool IsAbortConnect = false#region 构造函数 /// /// 缺省构造函数 /// public FTPClient() { strRemoteHost = ""strRemotePath = ""strRemoteUser = ""strRemotePass = ""strRemotePort = 21bConnected = false} /// /// 构造函数 /// /// FTP服务器IP地址 /// 当前服务器目录 /// 登录用户账号 /// 登录用户密码 /// FTP服务器端口 public FTPClient(string remoteHost, string remotePath, string remoteUser, string remotePass, int remotePort) { strRemoteHost = remoteHoststrRemotePath = remotePathstrRemoteUser = remoteUserstrRemotePass = remotePassstrRemotePort = remotePortConnect()} #endregion #region 登陆字段、属性 /// /// FTP服务器IP地址 /// private string strRemoteHostpublic string RemoteHost { get { return strRemoteHost} set { strRemoteHost = value} } /// /// FTP服务器端口 /// private int strRemotePortpublic int RemotePort { get { return strRemotePort} set { strRemotePort = value} } /// /// 当前服务器目录 /// private string strRemotePathpublic string RemotePath { get { return strRemotePath} set { strRemotePath = value} } /// /// 登录用户账号 /// private string strRemoteUserpublic string RemoteUser { set { strRemoteUser = value} } /// /// 用户登录密码 /// private string strRemotePasspublic string RemotePass { set { strRemotePass = value} } /// /// 是否登录 /// private Boolean bConnectedpublic bool Connected { get { return bConnected} } #endregion #region 链接 /// /// 建立连接 /// public void Connect() { //if (IsAbortConnect) throw new IOException("用户强制终止了FTP")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("无法连接到远程服务器!")} // 获取应答码 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// 切换到初始目录 if (!string.IsNullOrEmpty(strRemotePath)) { ChDir(strRemotePath)} } /// /// 关闭连接 /// public void DisConnect() { if (socketControl != null) { SendCommand("QUIT")} CloseSocketConnect()} public void AbortConnect() { if (socketControl != null) { SendCommand("ABOR")} IsAbortConnect = true//CloseSocketConnect()} #endregion #region 传输模式 /// /// 传输模式:二进制类型、ASCII类型 /// public enum TransferType { Binary, ASCII }/// /// 设置传输模式 /// /// 传输模式 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} } /// /// 获得传输模式 /// /// 传输模式 public TransferType GetTransferType() { return trType} #endregion #region 文件 *** 作 /// /// 获得文件列表 /// /// 文件名的匹配字符串 /// 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 += GB2312.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} /// /// 获取文件大小 /// /// 文件名 /// 文件大小 public long GetFileSize(string strFileName) { if (!bConnected) { Connect()} SendCommand("SIZE " + Path.GetFileName(strFileName))long lSize = 0if (iReplyCode == 213) { lSize = Int64.Parse(strReply.Substring(4))} else { throw new IOException(strReply.Substring(4))} return lSize} /// /// 删除 /// /// 待删除文件名 public void Delete(string strFileName) { if (!bConnected) { Connect()} SendCommand("DELE " + strFileName)if (iReplyCode != 250) { throw new IOException(strReply.Substring(4))} } /// /// 重命名(如果新文件名与已有文件重名,将覆盖已有文件) /// /// 旧文件名 /// 新文件名 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 上传和下载 /// /// 下载一批文件 /// /// 文件名的匹配字符串 /// 本地目录(不得以\结束) public void Get(string strFileNameMask, string strFolder) { if (!bConnected) { Connect()} string[] strFiles = Dir(strFileNameMask)foreach (string strFile in strFiles) { if (!strFile.Equals(""))//一般来说strFiles的最后一个元素可能是空字符串 { if (strFile.LastIndexOf(".") >-1) { Get(strFile.Replace("\r", ""), strFolder, strFile.Replace("\r", ""))} } } } /// /// 下载一个文件 /// /// 要下载的文件名 /// 本地目录(不得以\结束) /// 保存在本地时的文件名 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))} } } /// /// 上传一批文件 /// /// 本地目录(不得以\结束) /// 文件名匹配字符(可以包含*和?) public void Put(string strFolder, string strFileNameMask) { string[] strFiles = Directory.GetFiles(strFolder, strFileNameMask)foreach (string strFile in strFiles) { //strFile是完整的文件名(包含路径) Put(strFile)} } /// /// 上传一个文件 /// /// 本地文件名 public void Put(string strFileName) { if (!bConnected) { Connect()} UpdateStatus = trueSocket 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 = 0long total = input.Lengthlong finished = 0//DateTime startTime = DateTime.Nowdouble speed = 0while ((iBytes = input.Read(buffer, 0, buffer.Length)) >0) { Console.WriteLine(startTime.ToString())socketData.Send(buffer, iBytes, 0)DateTime endTime = DateTime.NowTimeSpan ts = endTime - startTimefinished += iBytesConsole.WriteLine(ts.Milliseconds)if (ts.Milliseconds >0) { speed = (double)(finished / ts.TotalMilliseconds)speed = Math.Round(speed * 1000 / 1024, 2)} if (OnTransferProcess != null&&iBytes>0&&finished>0) { OnTransferProcess(total, finished,speed)} } UpdateStatus = falsefinished = 0input.Close()if (socketData.Connected) { socketData.Close()} if (!(iReplyCode == 226 || iReplyCode == 250)) { ReadReply()if (!(iReplyCode == 226 || iReplyCode == 250)) { UpdateStatus = falsethrow new IOException(strReply.Substring(4))} } } #endregion #region 目录 *** 作 /// /// 创建目录 /// /// 目录名 public void MkDir(string strDirName) { if (!bConnected) { Connect()} SendCommand("MKD " + strDirName)if (iReplyCode != 257) { throw new IOException(strReply.Substring(4))} } /// /// 删除目录 /// /// 目录名 public void RmDir(string strDirName) { if (!bConnected) { Connect()} SendCommand("RMD " + strDirName)if (iReplyCode != 250) { throw new IOException(strReply.Substring(4))} } /// /// 改变目录 /// /// 新的工作目录名 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 内部变量 /// /// 服务器返回的应答信息(包含应答码) /// private string strMsg/// /// 服务器返回的应答信息(包含应答码) /// private string strReply/// /// 服务器返回的应答码 /// private int iReplyCode/// /// 进行控制连接的socket /// private Socket socketControl/// /// 传输模式 /// private TransferType trType/// /// 接收和发送数据的缓冲区 /// private static int BLOCK_SIZE = Int16.MaxValueByte[] buffer = new Byte[BLOCK_SIZE]/// /// 编码方式(为防止出现中文乱码采用 GB2312编码方式) /// Encoding GB2312 = Encoding.Default //Encoding.GetEncoding("gb2312")#endregion #region 内部函数 /// /// 将一行应答字符串记录在strReply和strMsg /// 应答码记录在iReplyCode /// private void ReadReply() { strMsg = ""strReply = ReadLine()iReplyCode = Int32.Parse(strReply.Substring(0, 3))} /// /// 建立进行数据连接的socket /// /// 数据连接socket 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.Lengthint partCount = 0string buf = ""for (int i = 0i <len &&partCount <= 6i++) { char ch = Char.Parse(ipData.Substring(i, 1))if (Char.IsDigit(ch)) buf += chelse 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("无法连接服务器")} return s} /// /// 关闭socket连接(用于登录以前) /// private void CloseSocketConnect() { if (socketControl != null) { socketControl.Close()socketControl = null} bConnected = false} /// /// 读取Socket返回的所有字符串 /// /// 包含应答码的字符串行 private string ReadLine() { while (true) { int iBytes = socketControl.Receive(buffer, buffer.Length, 0)strMsg += GB2312.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} /// /// 发送命令并获取应答码和最后一行应答字符串 /// /// 命令 private void SendCommand(String strCommand) { Byte[] cmdBytes = GB2312.GetBytes((strCommand + "\r

").ToCharArray())socketControl.Send(cmdBytes, cmdBytes.Length, 0)ReadReply()} #endregion } }

ftp(file transfer protocol)

功能说明:设置文件系统相关功能。

语法:ftp [-dignv][主机名称或IP地址]

补充说明:FTP是ARPANet的标准文件传输协议,该网络就是现今Internet的前身。

参数: 《Linux就该这么学》

-d 详细显示指令执行过程,便于排错或分析程序执行的情形。

-i 关闭互动模式,不询问任何问题。

-g 关闭本地主机文件名称支持特殊字符的扩充特性。

-n 不使用自动登陆。

-v 显示指令执行过程。

1. 连接ftp服务器

格式:ftp [hostname| ip-address]

a)在linux命令行下输入:

ftp 192.168.1.1

b)服务器询问你用户名和密码,分别输入用户名和相应密码,待认证通过即可。

c)也可以先输入ftp

ftp>

d)然后在输入要连接的IP

ftp>open 192.168.1.1

2. 下载文件

下载文件通常用get和mget这两条命令。

a) get

格式:get [remote-file] [local-file]

将文件从远端主机中传送至本地主机中。

如要获取远程服务器上/usr/your/1.htm,则

ftp>get /usr/your/1.htm 1.htm (回车)

b) mget

格式:mget [remote-files]

从远端主机接收一批文件至本地主机。

如要获取服务器上/usr/your/下的所有文件,则

ftp>cd /usr/your/

ftp>mget *.* (回车)

此时每下载一个文件,都会有提示。如果要除掉提示,则在mget *.* 命令前先执行:prompt off

注意:文件都下载到了linux主机的当前目录下。比如,在 /usr/my下运行的ftp命令,则文件都下载到了/usr/my下。

3.上传文件

a) put

格式:put local-file [remote-file]

将本地一个文件传送至远端主机中。

如要把本地的1.htm传送到远端主机/usr/your,并改名为2.htm

ftp>put 1.htm /usr/your/2.htm (回车)

b) mput

格式:mput local-files

将本地主机中一批文件传送至远端主机。

如要把本地当前目录下所有html文件上传到服务器/usr/your/ 下

ftp>cd /usr/your (回车)

ftp>mput *.htm (回车)


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/9007903.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-23
下一篇 2023-04-23

发表评论

登录后才能评论

评论列表(0条)

保存