FTPClientHelper辅助类 实现文件上传,目录操作,下载等操作
程序员文章站
2022-05-03 16:30:40
文档说明
本文档使用socket通信方式来实现ftp文件的上传下载等命令的执行
1.基本介绍
由于最近的项目是客户端的程序,需要将客户端的图片文件【切图】-【...
文档说明
本文档使用socket通信方式来实现ftp文件的上传下载等命令的执行
1.基本介绍
由于最近的项目是客户端的程序,需要将客户端的图片文件【切图】-【打包】-【ftp上传】,现在就差最后一步了,慢慢的把这些小功能实现了,合并到一起就是一个大功能了,所以一个业务需要拆分的很小很小才可以看清楚,这个项目实际需要用到哪些知识点,下面介绍一下ftp上传的命令
ftp命令的参考链接:
ftp适合小文件上传
对带宽要求要求较高
服务器安全性也要考虑到
命令需要熟悉,不然比较难
2.实际项目
文件上传
文件下载
删除文件
创建文件夹
文件夹重命名
删除文件夹
改变目录
获取文件夹中文件列表
等等
2.1 图片上传和下载
写了几个方法,一般用的最多的就是put,具体的可以下载复制源码下来进行实战一下。
2.2 目录创建和删除
这个方法今天刚好用上了,折腾了一会,才搞定的。
3.调用代码参考
由于这个帮助类不是静态的,所以需要实例化
string username = "xxx"; string password = "xxx"; var ftp = new ftpclienthelper("xxx", ".", username, password, 1021);
下面还是调用常用的方法,就可以了,因为账号、密码、服务器的ip地址都被我用“xxx”代替了,所以大家自己改下,还有ftp默认端口号是:1021,如果有变动还是需要自己改下的。
4.ftpclienthelper下载
//------------------------------------------------------------------------------------- // all rights reserved , copyright (c) 2015 , zto , ltd . //------------------------------------------------------------------------------------- using system; using system.io; using system.net; using system.net.sockets; using system.text; using system.threading; namespace zto.pictest.utilities { /// <summary> /// ftp操作帮助类 /// /// 修改纪录 /// /// 2016-4-4 版本:1.0 yanghenglian 创建主键,注意命名空间的排序,测试非常好。 /// /// 版本:1.0 /// /// <author> /// <name>yanghenglian</name> /// <date>2016-4-4</date> /// </author> /// </summary> public class ftpclienthelper { public static object obj = new object(); #region 构造函数 /// <summary> /// 缺省构造函数 /// </summary> public ftpclienthelper() { remotehost = ""; _strremotepath = ""; _strremoteuser = ""; _strremotepass = ""; _strremoteport = 21; _bconnected = false; } /// <summary> /// 构造函数 /// </summary> public ftpclienthelper(string remotehost, string remotepath, string remoteuser, string remotepass, int remoteport) { // ip地址 remotehost = remotehost; // 这个很重要,表示连接路径,如果是.表示根目录 _strremotepath = remotepath; // 登录账号 _strremoteuser = remoteuser; // 登录密码 _strremotepass = remotepass; // ftp端口号 _strremoteport = remoteport; connect(); } #endregion #region 字段 private int _strremoteport; private boolean _bconnected; private string _strremotepass; private string _strremoteuser; private string _strremotepath; /// <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 const int blocksize = 512; /// <summary> /// 编码方式 /// </summary> readonly encoding _ascii = encoding.ascii; /// <summary> /// 字节数组 /// </summary> readonly byte[] _buffer = new byte[blocksize]; #endregion #region 属性 /// <summary> /// ftp服务器ip地址 /// </summary> public string remotehost { get; set; } /// <summary> /// ftp服务器端口 /// </summary> public int remoteport { get { return _strremoteport; } set { _strremoteport = value; } } /// <summary> /// 当前服务器目录 /// </summary> public string remotepath { get { return _strremotepath; } set { _strremotepath = value; } } /// <summary> /// 登录用户账号 /// </summary> public string remoteuser { set { _strremoteuser = value; } } /// <summary> /// 用户登录密码 /// </summary> public string remotepass { set { _strremotepass = value; } } /// <summary> /// 是否登录 /// </summary> public bool connected { get { return _bconnected; } } #endregion #region 链接 /// <summary> /// 建立连接 /// </summary> public void connect() { lock (obj) { _socketcontrol = new socket(addressfamily.internetwork, sockettype.stream, protocoltype.tcp); var ep = new ipendpoint(ipaddress.parse(remotehost), _strremoteport); try { _socketcontrol.connect(ep); } catch (exception) { throw new ioexception("不能连接ftp服务器"); } } 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) { sendcommand(tttype == transfertype.binary ? "type i" : "type a"); if (_ireplycode != 200) { throw new ioexception(_strreply.substring(4)); } _trtype = tttype; } /// <summary> /// 获得传输模式 /// </summary> /// <returns>传输模式</returns> public transfertype gettransfertype() { return _trtype; } #endregion #region 文件操作 /// <summary> /// 获得文件列表 /// </summary> /// <param name="strmask">文件名的匹配字符串</param> public string[] dir(string strmask) { if (!_bconnected) { connect(); } socket socketdata = createdatasocket(); sendcommand("nlst " + strmask); if (!(_ireplycode == 150 || _ireplycode == 125 || _ireplycode == 226)) { throw new ioexception(_strreply.substring(4)); } _strmsg = ""; thread.sleep(2000); while (true) { int ibytes = socketdata.receive(_buffer, _buffer.length, 0); _strmsg += _ascii.getstring(_buffer, 0, ibytes); if (ibytes < _buffer.length) { break; } } char[] seperator = { '\n' }; string[] strsfilelist = _strmsg.split(seperator); socketdata.close(); //数据socket关闭时也会有返回码 if (_ireplycode != 226) { readreply(); if (_ireplycode != 226) { throw new ioexception(_strreply.substring(4)); } } return strsfilelist; } public void newputbyguid(string strfilename, string strguid) { if (!_bconnected) { connect(); } string str = strfilename.substring(0, strfilename.lastindexof("\\", stringcomparison.ordinal)); string strtypename = strfilename.substring(strfilename.lastindexof(".", stringcomparison.ordinal)); strguid = str + "\\" + strguid; socket socketdata = createdatasocket(); sendcommand("stor " + path.getfilename(strguid)); if (!(_ireplycode == 125 || _ireplycode == 150)) { throw new ioexception(_strreply.substring(4)); } var input = new filestream(strguid, filemode.open); input.flush(); int ibytes; 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)); } } } /// <summary> /// 获取文件大小 /// </summary> /// <param name="strfilename">文件名</param> /// <returns>文件大小</returns> public long getfilesize(string strfilename) { if (!_bconnected) { connect(); } sendcommand("size " + path.getfilename(strfilename)); long lsize; if (_ireplycode == 213) { lsize = int64.parse(_strreply.substring(4)); } else { throw new ioexception(_strreply.substring(4)); } return lsize; } /// <summary> /// 获取文件信息 /// </summary> /// <param name="strfilename">文件名</param> /// <returns>文件大小</returns> public string getfileinfo(string strfilename) { if (!_bconnected) { connect(); } socket socketdata = createdatasocket(); sendcommand("list " + strfilename); if (!(_ireplycode == 150 || _ireplycode == 125 || _ireplycode == 226 || _ireplycode == 250)) { throw new ioexception(_strreply.substring(4)); } byte[] b = new byte[512]; memorystream ms = new memorystream(); while (true) { int ibytes = socketdata.receive(b, b.length, 0); ms.write(b, 0, ibytes); if (ibytes <= 0) { break; } } byte[] bt = ms.getbuffer(); string strresult = encoding.ascii.getstring(bt); ms.close(); return strresult; } /// <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) { socket socketdata = createdatasocket(); try { if (!_bconnected) { connect(); } settransfertype(transfertype.binary); if (strlocalfilename.equals("")) { strlocalfilename = strremotefilename; } sendcommand("retr " + strremotefilename); if (!(_ireplycode == 150 || _ireplycode == 125 || _ireplycode == 226 || _ireplycode == 250)) { throw new ioexception(_strreply.substring(4)); } var output = new filestream(strfolder + "\\" + strlocalfilename, filemode.create); 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)); } } } catch { socketdata.close(); _socketcontrol.close(); _bconnected = false; _socketcontrol = null; } } /// <summary> /// 下载一个文件 /// </summary> /// <param name="strremotefilename">要下载的文件名</param> /// <param name="strfolder">本地目录(不得以\结束)</param> /// <param name="strlocalfilename">保存在本地时的文件名</param> public void getnobinary(string strremotefilename, string strfolder, string strlocalfilename) { if (!_bconnected) { connect(); } if (strlocalfilename.equals("")) { strlocalfilename = strremotefilename; } socket socketdata = createdatasocket(); sendcommand("retr " + strremotefilename); if (!(_ireplycode == 150 || _ireplycode == 125 || _ireplycode == 226 || _ireplycode == 250)) { throw new ioexception(_strreply.substring(4)); } var output = new filestream(strfolder + "\\" + strlocalfilename, filemode.create); 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) { put(strfile); } } /// <summary> /// 上传一个文件 /// </summary> /// <param name="strfilename">本地文件名</param> public void put(string strfilename) { if (!_bconnected) { connect(); } socket socketdata = createdatasocket(); if (path.getextension(strfilename) == "") sendcommand("stor " + path.getfilenamewithoutextension(strfilename)); else sendcommand("stor " + path.getfilename(strfilename)); if (!(_ireplycode == 125 || _ireplycode == 150)) { throw new ioexception(_strreply.substring(4)); } var input = new filestream(strfilename, filemode.open); int ibytes; 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)); } } } /// <summary> /// 上传一个文件 /// </summary> /// <param name="strfilename">本地文件名</param> /// /// <param name="strguid"> </param> public void putbyguid(string strfilename, string strguid) { if (!_bconnected) { connect(); } string str = strfilename.substring(0, strfilename.lastindexof("\\", stringcomparison.ordinal)); string strtypename = strfilename.substring(strfilename.lastindexof(".", system.stringcomparison.ordinal)); strguid = str + "\\" + strguid; file.copy(strfilename, strguid); file.setattributes(strguid, fileattributes.normal); socket socketdata = createdatasocket(); sendcommand("stor " + path.getfilename(strguid)); if (!(_ireplycode == 125 || _ireplycode == 150)) { throw new ioexception(_strreply.substring(4)); } var input = new filestream(strguid, filemode.open, system.io.fileaccess.read, system.io.fileshare.read); int ibytes = 0; while ((ibytes = input.read(_buffer, 0, _buffer.length)) > 0) { socketdata.send(_buffer, ibytes, 0); } input.close(); file.delete(strguid); 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> /// 将一行应答字符串记录在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]; var s = new socket(addressfamily.internetwork, sockettype.stream, protocoltype.tcp); var ep = new ipendpoint(ipaddress.parse(ipaddress), port); try { s.connect(ep); } catch (exception) { throw new ioexception("无法连接ftp服务器"); } return s; } /// <summary> /// 关闭socket连接(用于登录以前) /// </summary> private void closesocketconnect() { lock (obj) { if (_socketcontrol != null) { _socketcontrol.close(); _socketcontrol = null; } _bconnected = false; } } /// <summary> /// 读取socket返回的所有字符串 /// </summary> /// <returns>包含应答码的字符串行</returns> private string readline() { lock (obj) { while (true) { int ibytes = _socketcontrol.receive(_buffer, _buffer.length, 0); _strmsg += _ascii.getstring(_buffer, 0, ibytes); if (ibytes < _buffer.length) { break; } } } char[] seperator = { '\n' }; string[] mess = _strmsg.split(seperator); if (_strmsg.length > 2) { _strmsg = mess[mess.length - 2]; } else { _strmsg = mess[0]; } if (!_strmsg.substring(3, 1).equals(" ")) //返回字符串正确的是以应答码(如220开头,后面接一空格,再接问候字符串) { return readline(); } return _strmsg; } /// <summary> /// 发送命令并获取应答码和最后一行应答字符串 /// </summary> /// <param name="strcommand">命令</param> public void sendcommand(string strcommand) { lock (obj) { byte[] cmdbytes = encoding.ascii.getbytes((strcommand + "\r\n").tochararray()); _socketcontrol.send(cmdbytes, cmdbytes.length, 0); thread.sleep(100); readreply(); } } #endregion } }
5.ftp常用的命令
#region 程序集 system.dll, v4.0.0.0 // c:\program files (x86)\reference assemblies\microsoft\framework\.netframework\v4.0\system.dll #endregion using system; namespace system.net { // 摘要: // system.net.webrequestmethods.ftp、system.net.webrequestmethods.file 和 system.net.webrequestmethods.http // 类的容器类。无法继承此类 public static class webrequestmethods { // 摘要: // 表示可用于 file 请求的文件协议方法的类型。无法继承此类。 public static class file { // 摘要: // 表示用来从指定的位置检索文件的 file get 协议方法。 public const string downloadfile = "get"; // // 摘要: // 表示用来将文件复制到指定位置的 file put 协议方法。 public const string uploadfile = "put"; } // 摘要: // 表示可与 ftp 请求一起使用的 ftp 协议方法的类型。无法继承此类。 public static class ftp { // 摘要: // 表示要用于将文件追加到 ftp 服务器上的现有文件的 ftp appe 协议方法。 public const string appendfile = "appe"; // // 摘要: // 表示要用于删除 ftp 服务器上的文件的 ftp dele 协议方法。 public const string deletefile = "dele"; // // 摘要: // 表示要用于从 ftp 服务器下载文件的 ftp retr 协议方法。 public const string downloadfile = "retr"; // // 摘要: // 表示要用于从 ftp 服务器上的文件检索日期时间戳的 ftp mdtm 协议方法。 public const string getdatetimestamp = "mdtm"; // // 摘要: // 表示要用于检索 ftp 服务器上的文件大小的 ftp size 协议方法。 public const string getfilesize = "size"; // // 摘要: // 表示获取 ftp 服务器上的文件的简短列表的 ftp nlist 协议方法。 public const string listdirectory = "nlst"; // // 摘要: // 表示获取 ftp 服务器上的文件的详细列表的 ftp list 协议方法。 public const string listdirectorydetails = "list"; // // 摘要: // 表示在 ftp 服务器上创建目录的 ftp mkd 协议方法。 public const string makedirectory = "mkd"; // // 摘要: // 表示打印当前工作目录的名称的 ftp pwd 协议方法。 public const string printworkingdirectory = "pwd"; // // 摘要: // 表示移除目录的 ftp rmd 协议方法。 public const string removedirectory = "rmd"; // // 摘要: // 表示重命名目录的 ftp rename 协议方法。 public const string rename = "rename"; // // 摘要: // 表示将文件上载到 ftp 服务器的 ftp stor 协议方法。 public const string uploadfile = "stor"; // // 摘要: // 表示将具有唯一名称的文件上载到 ftp 服务器的 ftp stou 协议方法。 public const string uploadfilewithuniquename = "stou"; } // 摘要: // 表示可与 http 请求一起使用的 http 协议方法的类型。 public static class http { // 摘要: // 表示与代理一起使用的 http connect 协议方法,该代理可以动态切换到隧道,如 ssl 隧道的情况。 public const string connect = "connect"; // // 摘要: // 表示一个 http get 协议方法。 public const string get = "get"; // // 摘要: // 表示一个 http head 协议方法。除了服务器在响应中只返回消息头不返回消息体以外,head 方法和 get 是一样的。 public const string head = "head"; // // 摘要: // 表示一个 http mkcol 请求,该请求在请求 uri(统一资源标识符)指定的位置新建集合,如页的集合。 public const string mkcol = "mkcol"; // // 摘要: // 表示一个 http post 协议方法,该方法用于将新实体作为补充发送到某个 uri。 public const string post = "post"; // // 摘要: // 表示一个 http put 协议方法,该方法用于替换 uri 标识的实体。 public const string put = "put"; } } }
以上就是本文的全部内容,希望能给大家一个参考,也希望大家多多支持。
上一篇: asp中用for循环的一个小技巧