利用org.apache.commons.net.ftp包实现一个简单的ftp客户端实用类。主要实现一下功能
1.支持上传下载。支持断点续传
2.支持进度汇报
3.支持对于中文目录及中文文件创建的支持。
import
java.io.File;
import
java.io.FileOutputStream;
import
java.io.IOException;
import
java.io.InputStream;
import
java.io.OutputStream;
import
java.io.PrintWriter;
import
java.io.RandomAccessFile;
import
open.mis.data.DownloadStatus;
import
open.mis.data.UploadStatus;
import
org.apache.commons.net.PrintCommandListener;
import
org.apache.commons.net.ftp.FTP;
import
org.apache.commons.net.ftp.FTPClient;
import
org.apache.commons.net.ftp.FTPFile;
import
org.apache.commons.net.ftp.FTPReply;

/** */
/**
* 支持断点续传的FTP实用类
*
@author
BenZhou
http://www.bt285.cn
*
@version
0.1 实现基本断点上传下载
*
@version
0.2 实现上传下载进度汇报
*
@version
0.3 实现中文目录创建及中文文件创建,添加对于中文的支持
*/

public
class
ContinueFTP
{
public
FTPClient ftpClient
=
new
FTPClient();

public
ContinueFTP()
{
//
设置将过程中使用到的命令输出到控制台
this
.ftpClient.addProtocolCommandListener(
new
PrintCommandListener(
new
PrintWriter(System.out)));
}

/** */
/**
* 连接到FTP服务器
*
@param
hostname 主机名
*
@param
port 端口
*
@param
username 用户名
*
@param
password 密码
*
@return
是否连接成功
*
@throws
IOException
*/

public
boolean
connect(String hostname,
int
port,String username,String password)
throws
IOException
{
ftpClient.connect(hostname, port);
ftpClient.setControlEncoding(
"
GBK
"
);

if
(FTPReply.isPositiveCompletion(ftpClient.getReplyCode()))
{

if
(ftpClient.login(username, password))
{
return
true
;
}
}
disconnect();
return
false
;
}

/** */
/**
* 从FTP服务器上下载文件,支持断点续传,上传百分比汇报
*
@param
remote 远程文件路径
*
@param
local 本地文件路径
*
@return
上传的状态
*
@throws
IOException
*/

public
DownloadStatus download(String remote,String local)
throws
IOException
{
//
设置被动模式
ftpClient.enterLocalPassiveMode();
//
设置以二进制方式传输
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
DownloadStatus result;
//
检查远程文件是否存在
FTPFile[] files
=
ftpClient.listFiles(
new
String(remote.getBytes(
"
GBK
"
),
"
iso-8859-1
"
));

if
(files.length
!=
1
)
{
System.out.println(
"
远程文件不存在
"
);
return
DownloadStatus.Remote_File_Noexist;
}
long
lRemoteSize
=
files[
0
].getSize();
File f
=
new
File(local);
//
本地存在文件,进行断点下载

if
(f.exists())
{
long
localSize
=
f.length();
//
判断本地文件大小是否大于远程文件大小

if
(localSize
>=
lRemoteSize)
{
System.out.println(
"
本地文件大于远程文件,下载中止
"
);
return
DownloadStatus.Local_Bigger_Remote;
}
//
进行断点续传,并记录状态
FileOutputStream out
=
new
FileOutputStream(f,
true
);
ftpClient.setRestartOffset(localSize);
InputStream in
=
ftpClient.retrieveFileStream(
new
String(remote.getBytes(
"
GBK
"
),
"
iso-8859-1
"
));
byte
[] bytes
=
new
byte
[
1024
];
long
step
=
lRemoteSize
/
100
;
long
process
=
localSize
/
step;
int
c;

while
((c
=
in.read(bytes))
!=
-
1
)
{
out.write(bytes,
0
,c);
localSize
+=
c;
long
nowProcess
=
localSize
/
step;

if
(nowProcess
>
process)
{
process
=
nowProcess;
if
(process
%
10
==
0
)
System.out.println(
"
下载进度:
"
+
process);
//
TODO 更新文件下载进度,值存放在process变量中
}
}
in.close();
out.close();
boolean
isDo
=
ftpClient.completePendingCommand();

if
(isDo)
{
result
=
DownloadStatus.Download_From_Break_Success;

}
else
{
result
=
DownloadStatus.Download_From_Break_Failed;
}

}
else
{
OutputStream out
=
new
FileOutputStream(f);
InputStream in
=
ftpClient.retrieveFileStream(
new
String(remote.getBytes(
"
GBK
"
),
"
iso-8859-1
"
));
byte
[] bytes
=
new
byte
[
1024
];
long
step
=
lRemoteSize
/
100
;
long
process
=
0
;
long
localSize
=
0L
;
int
c;

while
((c
=
in.read(bytes))
!=
-
1
)
{
out.write(bytes,
0
, c);
localSize
+=
c;
long
nowProcess
=
localSize
/
step;

if
(nowProcess
>
process)
{
process
=
nowProcess;
if
(process
%
10
==
0
)
System.out.println(
"
下载进度:
"
+
process);
//
TODO 更新文件下载进度,值存放在process变量中
}
}
in.close();
out.close();
boolean
upNewStatus
=
ftpClient.completePendingCommand();

if
(upNewStatus)
{
result
=
DownloadStatus.Download_New_Success;

}
else
{
result
=
DownloadStatus.Download_New_Failed;
}
}
return
result;
}

/** */
/**
* 上传文件到FTP服务器,支持断点续传
*
@param
local 本地文件名称,绝对路径
*
@param
remote 远程文件路径,使用/home/directory1/subdirectory/file.ext或是
http://www.guihua.org
/subdirectory/file.ext 按照Linux上的路径指定方式,支持多级目录嵌套,支持递归创建不存在的目录结构
*
@return
上传结果
*
@throws
IOException
*/

public
UploadStatus upload(String local,String remote)
throws
IOException
{
//
设置PassiveMode传输
ftpClient.enterLocalPassiveMode();
//
设置以二进制流的方式传输
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
ftpClient.setControlEncoding(
"
GBK
"
);
UploadStatus result;
//
对远程目录的处理
String remoteFileName
=
remote;

if
(remote.contains(
"
/
"
))
{
remoteFileName
=
remote.substring(remote.lastIndexOf(
"
/
"
)
+
1
);
//
创建服务器远程目录结构,创建失败直接返回

if
(CreateDirecroty(remote, ftpClient)
==
UploadStatus.Create_Directory_Fail)
{
return
UploadStatus.Create_Directory_Fail;
}
}
//
检查远程是否存在文件
FTPFile[] files
=
ftpClient.listFiles(
new
String(remoteFileName.getBytes(
"
GBK
"
),
"
iso-8859-1
"
));

if
(files.length
==
1
)
{
long
remoteSize
=
files[
0
].getSize();
File f
=
new
File(local);
long
localSize
=
f.length();

if
(remoteSize
==
localSize)
{
return
UploadStatus.File_Exits;

}
else
if
(remoteSize
>
localSize)
{
return
UploadStatus.Remote_Bigger_Local;
}
//
尝试移动文件内读取指针,实现断点续传
result
=
uploadFile(remoteFileName, f, ftpClient, remoteSize);
//
如果断点续传没有成功,则删除服务器上文件,重新上传

if
(result
==
UploadStatus.Upload_From_Break_Failed)
{

if
(
!
ftpClient.deleteFile(remoteFile