jdk 自带的ftpclient 源码解析
sun.net.ftp.FtpClient
1 首先是 create 方法: 构造FtpClient 对象
public static FtpClient create() {
FtpClientProvider var0 = FtpClientProvider.provider();
return var0.createFtpClient();
}
public static FtpClient create(InetSocketAddress var0) throws FtpProtocolException, IOException {
FtpClient var1 = create();
if (var0 != null) {
var1.connect(var0);
}
return var1;
}
public static FtpClient create(String var0) throws FtpProtocolException, IOException {
return create(new InetSocketAddress(var0, 21));
}
2 如果创建FtpClient对象的时候参数里有 host 和port 则会默认调用connect (InetSocketAddress v)方法:
如果没有,则需要客户端主动调用connect 方法
connect 方法做的事情就是创建一个socket 连接,并初始化inputstream 和outputstream 对象
public sun.net.ftp.FtpClient connect(SocketAddress var1) throws FtpProtocolException, IOException {
return this.connect(var1, -1);
}
public sun.net.ftp.FtpClient connect(SocketAddress var1, int var2) throws FtpProtocolException, IOException {
if (!(var1 instanceof InetSocketAddress)) {
throw new IllegalArgumentException("Wrong address type");
} else {
this.serverAddr = (InetSocketAddress)var1;
this.tryConnect(this.serverAddr, var2);
if (!this.readReply()) {
throw new FtpProtocolException("Welcome message: " + this.getResponseString(), this.lastReplyCode);
} else {
this.welcomeMsg = this.getResponseString().substring(4);
return this;
}
}
}
--------------------
private void tryConnect(InetSocketAddress var1, int var2) throws IOException {
if (this.isConnected()) {
this.disconnect();
}
this.server = this.doConnect(var1, var2);
try {
this.out = new PrintStream(new BufferedOutputStream(this.server.getOutputStream()), true, encoding);
} catch (UnsupportedEncodingException var4) {
throw new InternalError(encoding + "encoding not found", var4);
}
this.in = new BufferedInputStream(this.server.getInputStream());
}
---------------
private Socket doConnect(InetSocketAddress var1, int var2) throws IOException {
Socket var3;
if (this.proxy != null) {
if (this.proxy.type() == Type.SOCKS) {
var3 = (Socket)AccessController.doPrivileged(new PrivilegedAction<Socket>() {
public Socket run() {
return new Socket(FtpClient.this.proxy);
}
});
} else {
var3 = new Socket(Proxy.NO_PROXY);
}
} else {
var3 = new Socket();
}
if (var2 >= 0) {
var3.connect(var1, var2);
} else if (this.connectTimeout >= 0) {
var3.connect(var1, this.connectTimeout);
} else if (defaultConnectTimeout > 0) {
var3.connect(var1, defaultConnectTimeout);
} else {
var3.connect(var1);
}
if (this.readTimeout >= 0) {
var3.setSoTimeout(this.readTimeout);
} else if (defaultSoTimeout > 0) {
var3.setSoTimeout(defaultSoTimeout);
}
return var3;
}
3 然后是登录操作:
public sun.net.ftp.FtpClient login(String var1, char[] var2) throws FtpProtocolException, IOException {
if (!this.isConnected()) {
throw new FtpProtocolException("Not connected yet", FtpReplyCode.BAD_SEQUENCE);
} else if (var1 != null && var1.length() != 0) {
this.tryLogin(var1, var2);
StringBuffer var4 = new StringBuffer();
for(int var5 = 0; var5 < this.serverResponse.size(); ++var5) {
String var3 = (String)this.serverResponse.elementAt(var5);
if (var3 != null) {
if (var3.length() >= 4 && var3.startsWith("230")) {
var3 = var3.substring(4);
}
var4.append(var3);
}
}
this.welcomeMsg = var4.toString();
this.loggedIn = true;
return this;
} else {
throw new IllegalArgumentException("User name can't be null or empty");
}
}
public sun.net.ftp.FtpClient login(String var1, char[] var2, String var3) throws FtpProtocolException, IOException {
if (!this.isConnected()) {
throw new FtpProtocolException("Not connected yet", FtpReplyCode.BAD_SEQUENCE);
} else if (var1 != null && var1.length() != 0) {
this.tryLogin(var1, var2);
if (this.lastReplyCode == FtpReplyCode.NEED_ACCOUNT) {
this.issueCommandCheck("ACCT " + var3);
}
StringBuffer var4 = new StringBuffer();
if (this.serverResponse != null) {
Iterator var5 = this.serverResponse.iterator();
while(var5.hasNext()) {
String var6 = (String)var5.next();
if (var6 != null) {
if (var6.length() >= 4 && var6.startsWith("230")) {
var6 = var6.substring(4);
}
var4.append(var6);
}
}
}
this.welcomeMsg = var4.toString();
this.loggedIn = true;
return this;
} else {
throw new IllegalArgumentException("User name can't be null or empty");
}
}
------------
可以看到这个方法先发送了一个USER命令 ,发现需要密码,有发送了一个 PASS 命令
private void tryLogin(String var1, char[] var2) throws FtpProtocolException, IOException {
this.issueCommandCheck("USER " + var1);
if (this.lastReplyCode == FtpReplyCode.NEED_PASSWORD && var2 != null && var2.length > 0) {
this.issueCommandCheck("PASS " + String.valueOf(var2));
}
}
4 用户登录成功之后可以进行其他操作
首先设置一些 属性
然后可以切换目录
还可以上传文件
下载文件
查看文件列表
删除目录 删除文件,重命名文件
public abstract FtpClient deleteFile(String var1) throws FtpProtocolException, IOException;
还可以获取一些配置信息,文件信息或者连接信息
5 上传文件的源码
public OutputStream putFileStream(String var1, boolean var2) throws FtpProtocolException, IOException {
String var3 = var2 ? "STOU " : "STOR ";
Socket var4 = this.openDataConnection(var3 + var1);
if (var4 == null) {
return null;
} else {
boolean var5 = this.type == TransferType.BINARY;
return new TelnetOutputStream(var4.getOutputStream(), var5);
}
}
public sun.net.ftp.FtpClient putFile(String var1, InputStream var2, boolean var3) throws FtpProtocolException, IOException {
String var4 = var3 ? "STOU " : "STOR ";
short var5 = 1500;
if (this.type == TransferType.BINARY) {
Socket var6 = this.openDataConnection(var4 + var1);
OutputStream var7 = this.createOutputStream(var6.getOutputStream());
byte[] var8 = new byte[var5 * 10];
int var9;
while((var9 = var2.read(var8)) >= 0) {
if (var9 > 0) {
var7.write(var8, 0, var9);
}
}
var7.close();
}
return this.completePending();
}