001.
//使用Sun的FtpClient做FTP上传下载
002.
import
sun.net.*;
003.
import
sun.net.ftp.*;
004.
import
java.io.*;
005.
import
java.util.*;
006.
/**
007.
FTP远程命令列表<br>
008.
USER PORT RETR ALLO DELE SITE XMKD CDUP FEAT<br>
009.
PASS PASV STOR REST CWD STAT RMD XCUP OPTS<br>
010.
ACCT TYPE APPE RNFR XCWD HELP XRMD STOU AUTH<br>
011.
REIN STRU SMNT RNTO LIST NOOP PWD SIZE PBSZ<br>
012.
QUIT MODE SYST ABOR NLST MKD XPWD MDTM PROT<br>
013.
在服务器上执行命令,如果用sendServer来执行远程命令(不能执行本地FTP命令)的话,所有FTP命令都要加上\r\n<br>
014.
ftpclient.sendServer("XMKD /test/bb\r\n"); //执行服务器上的FTP命令<br>
015.
ftpclient.readServerResponse一定要在sendServer后调用<br>
016.
nameList("/test")获取指目录下的文件列表<br>
017.
XMKD建立目录,当目录存在的情况下再次创建目录时报错<br>
018.
XRMD删除目录<br>
019.
DELE删除文件<br>
020.
* 针对FTP中的所有调用使用到文件名的地方请使用完整的路径名(绝对路径开始)。
021.
*/
022.
023.
public
class
FtpUtils {
024.
private
FtpClient ftpclient;
025.
private
String ipAddress;
026.
private
int
port;
027.
private
String username;
028.
private
String pass<a href=
"http://www.it165.net/edu/ebg/"
target=
"_blank"
class
=
"keylink"
>word</a>;
029.
/**
030.
* 构造函数
031.
* @param ip String 机器IP
032.
* @param port String 机器FTP端口号
033.
* @param username String FTP用户名
034.
* @param pass<a href="http://www.it165.net/edu/ebg/" target="_blank" class="keylink">word</a> String FTP密码
035.
* @throws Exception
036.
*/
037.
public
FtpUtils(String ip,
int
port, String username, String password)
throws
038.
Exception {
039.
this
.ipAddress = ip;
040.
this
.port = port;
041.
this
.ftpclient =
new
FtpClient(ipAddress, port);
042.
this
.username = username;
043.
this
.password = password;
044.
}
045.
/**
046.
* 构造函数
047.
* @param ip String 机器IP,默认端口为21
048.
* @param username String FTP用户名
049.
* @param password String FTP密码
050.
* @throws Exception
051.
*/
052.
public
FtpUtils(String ip, String username, String password)
throws
053.
Exception {
054.
this
(ip,
21
,username,password);
055.
}
056.
/**
057.
* 登录FTP服务器
058.
* @throws Exception
059.
*/
060.
public
void
login()
throws
Exception {
061.
ftpclient.login(username, password);
062.
}
063.
064.
/**
065.
* 退出FTP服务器
066.
* @throws Exception
067.
*/
068.
public
void
logout()
throws
Exception {
069.
//用ftpclient.closeServer()断开FTP出错时用下更语句退出
070.
ftpclient.sendServer(
"QUIT\r\n"
);
071.
int
reply = ftpclient.readServerResponse();
//取得服务器的返回信息
072.
}
073.
/**
074.
* 取得指定目录下的所有文件名,不包括目录名称
075.
* 分析nameList得到的输入流中的数,得到指定目录下的所有文件名
076.
* @param fullPath String
077.
* @return ArrayList
078.
* @throws Exception
079.
*/
080.
public
ArrayList fileNames(String fullPath)
throws
Exception {
081.
ftpclient.ascii();
//注意,使用字符模式
082.
TelnetInputStream list = ftpclient.nameList(fullPath);
083.
byte
[] names =
new
byte
[
2048
];
//如果文件数目很多,有可能溢出
084.
int
bufsize =
0
;
085.
bufsize = list.read(names,
0
, names.length);
//从流中读取
086.
list.close();
087.
ArrayList namesList =
new
ArrayList();
088.
int
i =
0
;
089.
int
j =
0
;
090.
while
(i < bufsize ) {
091.
if
(names[i] ==
10
) {
//字符模式为10,二进制模式为13
092.
String tempName =
new
String(names, j, i - j);
093.
namesList.add(tempName);
094.
//j = i + 2; //上一次位置二进制模式
095.
j = i +
1
;
//上一次位置字符模式
096.
}
097.
i = i +
1
;
098.
}
099.
return
namesList;
100.
}
101.
/**
102.
* 在FTP服务器上建立指定的目录,当目录已经存在的情下不会影响目录下的文件,这样用以判断FTP
103.
* 上传文件时保证目录的存在目录格式必须以"/"根目录开头
104.
* @param pathList String
105.
* @throws Exception
106.
*/
107.
public
void
buildRemoteDir(String pathList)
throws
Exception {
108.
ftpclient.ascii();
109.
StringTokenizer s =
new
StringTokenizer(pathList,
"/"
);
//sign
110.
int
count = s.countTokens();
111.
String pathName =
""
;
112.
while
(s.hasMoreElements()) {
113.
pathName = pathName +
"/"
+ (String) s.nextElement();
114.
try
{
115.
ftpclient.sendServer(
"XMKD "
+ pathName +
"\r\n"
);
116.
}
catch
(Exception e) {
117.
e =
null
;
118.
}
119.
int
reply = ftpclient.readServerResponse();
120.
}
121.
ftpclient.binary();
122.
}
123.
/**
124.
* 上传文件到FTP服务器,remote路径以FTP服务器的"/"开始,带文件名、
125.
* 上传文件只能使用二进制模式,当文件存在时再次上传则会覆盖
126.
* @param local String
127.
* @param remote String
128.
* @throws Exception
129.
*/
130.
public
void
upFile(String local, String remote)
throws
Exception {
131.
buildRemoteDir(remote.substring(
0
, remote.lastIndexOf(
"/"
)));
132.
ftpclient.binary();
//此行代码必须放在buildRemoteDir之后
133.
TelnetOutputStream ftpOut = ftpclient.put(remote);
134.
InputStream in =
new
FileInputStream(local);
//
135.
byte
[] buf =
new
byte
[
204800
];
136.
int
bufsize =
0
;
137.
while
((bufsize = in.read(buf,
0
, buf.length)) != -
1
){
138.
ftpOut.write(buf,
0
, bufsize);
139.
}
140.
in.close();
141.
ftpOut.close();
142.
}
143.
public
void
buildLocalDir(String fullPath)
throws
Exception {
144.
145.
if
(fullPath.lastIndexOf(
"/"
)<=
0
)
return
;
146.
String path=fullPath.substring(
0
,fullPath.lastIndexOf(
"/"
));
147.
148.
File f=
new
File(path);
149.
if
(!f.exists()){
150.
f.mkdirs();
151.
}
152.
}
153.
public
void
downFile(String remote,String local)
throws
Exception {
154.
buildLocalDir(local);
155.
ftpclient.binary();
//此行代码必须放在buildRemoteDir之后
156.
OutputStream out=
new
FileOutputStream(
new
File(local));
157.
TelnetInputStream ftpIn = ftpclient.get(remote);
158.
byte
[] buff=
new
byte
[
204800
];
159.
int
len=
0
;
160.
while
((len=ftpIn.read(buff))!=-
1
){
161.
out.write(buff,
0
,len);
162.
}
163.
out.close();
164.
ftpIn.close();
165.
}
166.
public
static
void
main(String args[])
throws
Exception{
167.
FtpUtils upfile=
new
FtpUtils(
"192.168.187.130"
,
"root"
,
"1-1=0"
);
168.
upfile.login();
169.
List list=upfile.fileNames(
"/"
);
170.
System.out.println(list);
171.
upfile.upFile(
"FtpUtils.java"
,
"/root/xjs/test/FtpUtils.java"
);
172.
upfile.downFile(
"/root/xjs/2.txt"
,
"xjs/2.txt"
);
173.
upfile.logout();
174.
}
175.
}
176.
/*
177.
以sun开头的class不是java里面的标准类,而是sun公司自己的的class,因此,他们位于rt.jar当中。因此,jdk源代码中没有提供源文件。但是,可以用诸如jad之类的反编译工具进行反编译。
178.
实际上,基本原理就是利用Socket和ServerSocket来发送遵守FTP协议的消息,与FTP服务器进行交互。
179.
主要用到这么几个类:
180.
sun.net.ftp.FtpClient extends sun.net.TransferProtocolClient
181.
sun.net.TransferProtocolClient extends sun.net.NetworkClient
182.
sun.net.TelnetInputStream extends FilterInputStream
183.
sun.net.TelnetOutputStream extends BufferedOutputStream
184.
因为是使用被动模式,因此,客户端要去连接服务端,
185.
在FtpClient的源代码的openDataConnection(String s)方法中有这么一句:
186.
serversocket = new ServerSocket(0, 1);也就是客户端随便选择一个空闲端口。
187.
也就是说,sun的FtpClient不支持主动模式。
188.
*/