Posted on 2007-01-21 19:49
webabcd 阅读(28330)
评论(123) 编辑 收藏
原文地址:
http://www.c-sharpcorner.com/UploadFile/neo_matrix/SimpleFTP01172007082222AM/SimpleFTP.aspx[原文源码下载]
.net 2.0(c#)下简单的FTP应用程序
原文发布日期:2007.01.18
作者:
Neo Matrix翻译:
webabcd本文使用.net 2.0(c#)来实现一般的FTP功能
介绍
微软的.net framework 2.0相对于1.x来说增加了对FTP的支持。以前为了符合我的需求,我不等不使用第三方类库来实现FTP功能,但是为了可靠,还是使用.net framework的类比较好。我的这段代码没有做成可重复使用的类库的形式,但它却是比较容易理解的并能满足你的需求。它可以实现上传,下载,删除等任意功能。在这篇文章的后面将给大家出示.net 2.0下实现ftp的简单代码,使用的语言是c#。或许是因为这是.net新增的类,又或许是第三方类库已经能很好的实现你的需求,.net 2.0的这部分类库并没有得到足够的关注。
背景
作为我的工作的一部分,我已经使用了ftp模块,但是我只能在.net 1.1中去使用它,所以我不能深入的研究.net 2.0下ftp的实现。但是我相信,.ne 2.0下对ftp的支持是非常好的。
代码
不要忘记引入命名空间
using System.Net;
using System.IO;
下面的几个步骤包括了使用FtpWebRequest类实现ftp功能的一般过程
1、创建一个FtpWebRequest对象,指向ftp服务器的uri
2、设置ftp的执行方法(上传,下载等)
3、给FtpWebRequest对象设置属性(是否支持ssl,是否使用二进制传输等)
4、设置登录验证(用户名,密码)
5、执行请求
6、接收相应流(如果需要的话)
7、如果没有打开的流,则关闭ftp请求
开发任何ftp应用程序都需要一个相关的ftp服务器及它的配置信息。FtpWebRequest暴露了一些属性来设置这些信息。
接下来的代码示例了上传功能
首先设置一个uri地址,包括路径和文件名。这个uri被使用在FtpWebRequest实例中。
然后根据ftp请求设置FtpWebRequest对象的属性
其中一些重要的属性如下:
·Credentials - 指定登录ftp服务器的用户名和密码。
·KeepAlive - 指定连接是应该关闭还是在请求完成之后关闭,默认为true
·UseBinary - 指定文件传输的类型。有两种文件传输模式,一种是Binary,另一种是ASCII。两种方法在传输时,字节的第8位是不同的。ASCII使用第8位作为错误控制,而Binary的8位都是有意义的。所以当你使用ASCII传输时要小心一些。简单的说,如果能用记事本读和写的文件用ASCII传输就是安全的,而其他的则必须使用Binary模式。当然使用Binary模式发送ASCII文件也是非常好的。
·UsePassive - 指定使用主动模式还是被动模式。早先所有客户端都使用主动模式,而且工作的很好,而现在因为客户端防火墙的存在,将会关闭一些端口,这样主动模式将会失败。在这种情况下就要使用被动模式,但是一些端口也可能被服务器的防火墙封掉。不过因为ftp服务器需要它的ftp服务连接到一定数量的客户端,所以他们总是支持被动模式的。这就是我们为什么要使用被动模式的原意,为了确保数据可以正确的传输,使用被动模式要明显优于主动模式。(译者注:主动(PORT)模式建立数据传输通道是由服务器端发起的,服务器使用20端口连接客户端的某一个大于1024的端口;在被动(PASV)模式中,数据传输的通道的建立是由FTP客户端发起的,他使用一个大于1024的端口连接服务器的1024以上的某一个端口)
·ContentLength - 设置这个属性对于ftp服务器是有用的,但是客户端不使用它,因为FtpWebRequest忽略这个属性,所以在这种情况下,该属性是无效的。但是如果我们设置了这个属性,ftp服务器将会提前预知文件的大小(在upload时会有这种情况)
·Method - 指定当前请求是什么命令(upload,download,filelist等)。这个值定义在结构体WebRequestMethods.Ftp中。
private void Upload(string filename)


{
FileInfo fileInf = new FileInfo(filename);
string uri = "ftp://" + ftpServerIP + "/" + fileInf.Name;
FtpWebRequest reqFTP;

// 根据uri创建FtpWebRequest对象
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + ftpServerIP + "/" + fileInf.Name));

// ftp用户名和密码
reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);

// 默认为true,连接不会被关闭
// 在一个命令之后被执行
reqFTP.KeepAlive = false;

// 指定执行什么命令
reqFTP.Method = WebRequestMethods.Ftp.UploadFile;

// 指定数据传输类型
reqFTP.UseBinary = true;

// 上传文件时通知服务器文件的大小
reqFTP.ContentLength = fileInf.Length;

// 缓冲大小设置为2kb
int buffLength = 2048;

byte[] buff = new byte[buffLength];
int contentLen;

// 打开一个文件流 (System.IO.FileStream) 去读上传的文件
FileStream fs = fileInf.OpenRead();
try

{
// 把上传的文件写入流
Stream strm = reqFTP.GetRequestStream();

// 每次读文件流的2kb
contentLen = fs.Read(buff, 0, buffLength);

// 流内容没有结束
while (contentLen != 0)

{
// 把内容从file stream 写入 upload stream
strm.Write(buff, 0, contentLen);

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

// 关闭两个流
strm.Close();
fs.Close();
}
catch (Exception ex)

{
MessageBox.Show(ex.Message, "Upload Error");
}
}
以上代码简单的示例了ftp的上传功能。创建一个指向某ftp服务器的FtpWebRequest对象,然后设置其不同的属性Credentials,KeepAlive,Method,UseBinary,ContentLength。
打开本地机器上的文件,把其内容写入ftp请求流。缓冲的大小为2kb,无论上传大文件还是小文件,这都是一个合适的大小。
private void Download(string filePath, string fileName)


{
FtpWebRequest reqFTP;

try

{
FileStream outputStream = new FileStream(filePath + "\\" + fileName, FileMode.Create);

reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + ftpServerIP + "/" + fileName));

reqFTP.Method = WebRequestMethods.Ftp.DownloadFile;

reqFTP.UseBinary = true;

reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);

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

Stream ftpStream = response.GetResponseStream();

long cl = response.ContentLength;

int bufferSize = 2048;

int readCount;

byte[] buffer = new byte[bufferSize];

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

while (readCount > 0)

{
outputStream.Write(buffer, 0, readCount);

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

ftpStream.Close();

outputStream.Close();

response.Close();
}
catch (Exception ex)

{
MessageBox.Show(ex.Message);
}
}
上面的代码实现了从ftp服务器上下载文件的功能。这不同于之前所提到的上传功能,下载需要一个响应流,它包含着下载文件的内容。这个下载的文件是在FtpWebRequest对象中的uri指定的。在得到所请求的文件后,通过FtpWebRequest对象的GetResponse()方法下载文件。它将把文件作为一个流下载到你的客户端的机器上。
注意:我们可以设置文件在我们本地机器上的存放路径和名称。
public string[] GetFileList()


{
string[] downloadFiles;
StringBuilder result = new StringBuilder();
FtpWebRequest reqFTP;
try

{
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + ftpServerIP + "/"));
reqFTP.UseBinary = true;
reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
reqFTP.Method = WebRequestMethods.Ftp.ListDirectory;
WebResponse response = reqFTP.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string line = reader.ReadLine();
while (line != null)

{
result.Append(line);
result.Append("\n");
line = reader.ReadLine();
}
// to remove the trailing '\n'
result.Remove(result.ToString().LastIndexOf('\n'), 1);
reader.Close();
response.Close();
return result.ToString().Split('\n');
}
catch (Exception ex)

{
System.Windows.Forms.MessageBox.Show(ex.Message);
downloadFiles = null;
return downloadFiles;
}
}
上面的代码示例了如何从ftp服务器上获得文件列表。uri指向ftp服务器的地址。我们使用StreamReader对象来存储一个流,文件名称列表通过“\r\n”分隔开,也就是说每一个文件名称都占一行。你可以使用StreamReader对象的ReadToEnd()方法来得到文件列表。上面的代码中我们用一个StringBuilder对象来保存文件名称,然后把结果通过分隔符分开后作为一个数组返回。我确定只是一个比较好的方法。
其他的实现如Rename,Delete,GetFileSize,FileListDetails,MakeDir等与上面的几段代码类似,就不多说了。
注意:实现重命名的功能时,要把新的名字设置给FtpWebRequest对象的RenameTo属性。连接指定目录的时候,需要在FtpWebRequest对象所使用的uri中指明。
需要注意的地方
你在编码时需要注意以下几点:
·除非EnableSsl属性被设置成true,否作所有数据,包括你的用户名和密码都将明文发给服务器,任何监视网络的人都可以获取到你连接服务器的验证信息。如果你连接的ftp服务器提供了SSL,你就应当把EnableSsl属性设置为true。
·如果你没有访问ftp服务器的权限,将会抛出SecurityException错误
·发送请求到ftp服务器需要调用GetResponse方法。当请求的操作完成后,一个FtpWebResponse对象将返回。这个FtpWebResponse对象提供了操作的状态和已经从ftp服务器上下载的数据。FtpWebResponse对象的StatusCode属性提供了ftp服务器返回的最后的状态代码。FtpWebResponse对象的StatusDescription属性为这个状态代码的描述。
Feedback
白费功夫了,想要把这段代码移到PPC开发环境中,发现.net CF 中没有System.Net.FTPWebRequest类,苦啊
@cndwd
惭愧啊,关注多天,没解决问题
没有System.Net.FTPWebRequest的话就
那有System.Net命名空间吗?
有的话可以用1.1时候的开源的第三方类库
@webabcd
客气了,有System.Net命名控件
我查查资料试试,多谢了
webabcd ,你好,我有来了,想请教您另一种实现ftp应用程序方法里的问题。问题代码部分:
private void SendCommand(string strCommand)
{
Byte[] cmdBytes = ASCII.GetBytes((strCommand + "\r\n").ToCharArray());
socketControl.Send(cmdBytes, cmdBytes.Length, 0);
ReadReply();
}
调用为SendCommand("NLST " + strMask);//strMask为string类型远端目录名
得到的列表包含了所有strMask目录下的非文件夹文件的名字,为什么没有文件夹 列表中没有啊?
麻烦你了
有哪位知道用2.0实现ftp断点续传的功能,最好能有demo,thank u!
@charles
这个,带源码的
http://www.enterprisedt.com/products/edtftpnet/overview.html
如果FTP服务器不用默认的21端口,程序中改如何修改?
如果FTP服务器不用默认的21端口,程序中改如何修改?
如果FTP服务器不用默认的21端口,程序中改如何修改?
如果FTP服务器不用默认的21端口,程序中改如何修改?
如果FTP服务器不用默认的21端口,程序中改如何修改?
@sunny
注意这句
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + ftpServerIP + "/" + fileInf.Name));
参数是个uri
你可以设置uri的port
thank you for webabcd. edtftpnet我这边有一个,我用反射看了他的源码结构,他的实现是基于ftp协议的,而且下的demo是怎样调用它的组件的demo,我想找个基于asp.net 2.0中ftpwebrequest/ftpwebresponse的实现断点续传(主要是上传)的demo。msdn中有讲怎样下载一个已经下载一半的文件,但是上传与下载还是有很多区别的,最重要的是断点是网络断了而程序不能断这样才能实现不停的上传而且要有offset这个值,难度还是不小的,我研究了一天都感觉很不对劲的
@charles
兄弟可以多写点文字说明,然后发到首页大家讨论
我这里人不多啊
@ivw
示例中有一个Download()方法
按你的需要下载文件就行了
方法不是判断每个文件的日期吧?如果这样的话文件多的时候时间不是很长吗?
@ivw
单写一个方法,判断日期和文件大小,如果是需要更新的文件则下载
楼主大大请问我用了上传的功能,一直显示 ftp 550错误
找不到文件名之类的,我下载了那个老外网站的源码,也是同样的提示,为什么呢????
远程服务器返回错误: (550) 文件不可用(例如,未找到文件,无法访问文件)。
@redcar
FTP服务器的配置问题,你可以换一个客户端或者用cmd测试一下FTP服务是否OK
远程服务器返回错误: (550) 文件不可用(例如,未找到文件,无法访问文件)。
可能是这里疏忽了。
string uri = "ftp://" + ftpServerIP + "/" + fileInf.Name;
FtpWebRequest reqFTP;
// 根据uri创建FtpWebRequest对象
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + ftpServerIP + "/" + fileInf.Name));
为什么申明个变量又不用?!
公司正让我写个自动更新,参考下。
又找到个好东西,记录一下。
WFsoft.wfLibrary.wfVerifyImage v1.6
http://www.wfsoft.com/wf_wfVerifyImage.asp
在本机没问题,传到服务器上就出问题.提示:找不到文件!
因为在本机发布的时候上传文件,程序是找到本机路径上的所上传的文件,而在服务器上传的时候它也会自动去寻找服务上路径的文件,但那个文件是在本机上,服务器根本没有这个文件,不知道怎么解决这个问题!(例如:在本机上传的时候文件路径在:d:/1.jpg上,所以在本机上发布的时候是找本机d:/1.jpg文件,然后上传到你所指定的目录中,而发布到服务器上后,上传本机的1.jpg文件到服务品上,服务器也会去找d:/1.jpg文件,但此文件在客户端而不在服务器上,所以提示找不到文件)
不知道楼主遇到过这个问题没,郁闷啊,不知道怎么解决!
@Gmtim
对呀
在服务器上当然找不到你客户端的文件,所以要把程序部署在你的客户端上
@小蜜蜂
示例代码中有现成的方法啊
Upload()
我想在上传文件的同时,在FTP服务器新增一个文件夹,并把这个文件放在这个文件夹中,应该怎么做啊?
我是菜鸟,麻烦你给写写代码好不好,多谢,嘿嘿
@小蜜蜂
文章内只是给出关键的代码
在源代码中是有新建目录的实现方法的,兄弟可以下载一下源代码看看,很详细的,也很清楚
我用上面的代码Download,去下载国外Ftp的文件可以,国内用xinwen365的免费空间就不行了“基础连接已经关闭:服务器提交了协议冲突”,怎么回事啊?不支持中文码?
@sunoy
应该不是不支持中文码的问题,因为我调试的时候就是连的我自己搭的ftp
为什么我用你上面的代码,该改的都改为什么老是从别人的机子上传到我的机子就老是抱找不到那文件,急啊
在本机没问题,传到服务器上就出问题.提示:找不到文件!
因为在本机发布的时候上传文件,程序是找到本机路径上的所上传的文件,而在服务器上传的时候它也会自动去寻找服务上路径的文件,但那个文件是在本机上,服务器根本没有这个文件,不知道怎么解决这个问题!(例如:在本机上传的时候文件路径在:d:/1.jpg上,所以在本机上发布的时候是找本机d:/1.jpg文件,然后上传到你所指定的目录中,而发布到服务器上后,上传本机的1.jpg文件到服务品上,服务器也会去找d:/1.jpg文件,但此文件在客户端而不在服务器上,所以提示找不到文件)
楼主我也是这样的问题
@haohao1
是的
部署在服务器上当然找不到你客户端的文件,所以要把程序部署在你的客户端上
不明白啊,怎么部署啊 119552380 可以加我QQ吗,我有几个问题问你
我的FTP已经部署在客户端,我用的是SER-U他已经帮你构造好了的
@haohao1
加msn吧
webabcd
hotmail
com
今天用了GetFileList和Download方法
private void ProcessCommand()
{
string[] filenames = GetFileList();
foreach (string filename in filenames) {
if (filename.EndsWith(".txt"))
if (!File.Exists(Config.LocalDir + filename)) {
Download(Config.LocalDir, filename);
WriteLog("下载文件:" + filename);
}
}
}
windows mobile上的FTP怎么作?那位知晓啊!帮忙指点指点!
@JASON xie
从没做过windows mobile的开发啊
楼主,你好,看了你的文章,深受启发,我下了源码,但是连不上,还有些问题,请问你的邮箱或其它联系方式是什么?谢谢
@凌霄云
可以msn我
webabcd
hotmail
com
FileInfo fileInf = new FileInfo(filename);
报错:找不到文件
好像打开的是服务器端的文件,怎么解决?
@青青
filename就是文件路径啊,你部署程序的机器要能访问这个路径才行啊
你好,我的ftp服务器是用IIS设置的,防火墙打开了21端口,然后用你贴出的程序不能上传文件,关闭防火墙后可以上传。
iis的ftp是port模式的,但是贴出来的程序是pasv模式的。能否指点一下如何改写成port模式的呢?
邮箱hd211314@yahoo.com.cn qq172166566
谢谢
@khkly
可以使用FtpWebRequest对象的UsePassive属性
问下 我的QQ:2646883(看到了联系一下哦谢谢)
怎么报530的错误了
就是说我未能登入
运行这代码时报出来的
// 把上传的文件写入流
Stream strm = reqFTP.GetRequestStream();
@bomanna
没记错的话
530应该是用户名密码不对
很少上qq
msn吧
webabcd
hotmail
com
请教一下,您的这段程序用在 winform下是没有问题的,但是当我把它迁移到,winweb下 btnDownload_Click(object sender, EventArgs e) 这个方法中的 FolderBrowserDialog fldDlg = new FolderBrowserDialog(); 是有问题的,应该如何更改这个对象,使得在web中也能谈出选择路径的窗体,谢谢!
@TomCat80529
asp.net里的FileUpload控件啊
@冰月
自己写个日志类,需要写日志的时候调用它就行了啊
关于C# FTP文件问题:
下载时怎样改变文件下载路径 ,也就是说怎样将下载文件下载到指定的文件目录(自己新建的)下呢?
------------------请多多关照。
@jun55xiu
不是有这个Download(string filePath, string fileName)方法吗
可以指定下载路径啊
你好,我想问下,比如下载文件的请求是什么时候发生的?
是ftpClient.Method = WebRequestMethods.Ftp.DownloadFile;
还是ftpClient.GetResponse();
另外个问题是能不能象DOS命令那样,先执行FTP的连接
然后执行下载,删除这些请求,现在看好像是设置FtpWebRequest,不知道是不是连接和请求一起发生,不知道能不能分开控制。
@cc_net
GetResponse();的时候
FtpWebRequest把相关的工作都封装到一起了
想分开控制的话就不能用FtpWebRequest
你好,我想问一下,你的上面那个代码怎么运行,我不太理解这东西,还有就是你定义的filename从那里来?怎么设置IIS的FTP服务器?
@345
:)
嗯。。。
贴出来的只是关键代码,请下载全部源代码看,就清楚了
ftp的基础和ftp服务器的配置请google
你好webabcd:
我测试了下代码,在我自建的SER-U FTP服务器上可以正常使用,但是访问solais FTP时就提示"无法连接到远程服务器",是了主动和被动都不可以,请教下是什么问题,谢谢.
@lxb_ll
:)
如果serv-u可以的话,那么客户端程序就没问题
不知道“solais FTP”是什么,也是ftp服务端吗?应该是他的配置的问题,具体什么问题我也说不清楚
这些代码在什么地方找的呀,测试过吗
下载的时候 ContentLength 可以得到文件大小吗
@FTP
:)
当然测试过啊
文中有源代码下载的地址的
可以
有知道windos moblie下如何实现ftp的吗?
@danewebb
没做过windows moblie开发啊
请楼主帮看一下代码,谢谢。 从Stream strm = reqFTP.GetRequestStream();就开始出现异常—“远程服务器返回错误: (550) 文件不可用(例如,未找到文件,无法访问文件)”。
private string ftpServerIP, ftpUserID, ftpPassword;
private void button2_Click(object sender, EventArgs e)
{
ftpServerIP = "172.20.88.100/9210/ulk";
ftpUserID = "abcdef";
ftpPassword = "abcdef";
Upload("d:\\temp1.txt");
}
楼主:
我换了个服务器上传成功了,可能是服务器的设置问题吧,谢谢啦!!
@baiyang
550错误,请将FtpWebRequest对象的KeepAlive设置为false,保证在连接后关闭。
@Donot Forget
:)
多谢提供一种解决方案
我的是成功实现了.可是我用这个下载的XML.不能用程序读取,
可以用记事本打开
@qiuqingpo
:)
既然用记事本打开没问题,那么肯定是可以用程序读取的啊
是因为编码吧.可怪的.我又把文件读出重写一遍又好了,谢谢
楼主,为什么上传的时候要一次只读2kb呢,而不是一下子全读出来,每次少读一些速度会快吗?我以前是一下子全读的,但是发现文件大时,上传上去后打不开了,但是大小事对的,用来你的方法就好了。哈哈。谢谢了。
每次读2kb好像真的快了,我没有测试过,但是运行起来能感觉出来快了,可能把数据从大的字节数组放到流,或从流放到大的字节数组是个很费时的操作。
@会长
:)
解决了就好
对于读写大文件来说肯定需要缓冲区的
楼主,Download下载一个文件没有问题,批量下载文件就会有几个文件报
远程服务器返回错误:(500)语法错误,无法识别命令。
且如果只有3byte大小的文件,下载下来以后就是0byte
请楼主帮帮忙了
@yj_yj
这个。。。
如果下一个文件没问题,那么这个示例代码就是没问题的
具体你的是什么问题,我不太清楚