使用 commons-net-3.6.jar
public class ApacheFtpUtil {
private Logger log = LoggerFactory.getLogger(ApacheFtpUtil.class);
private String host;
private String username;
private String password;
// 控制端口
private int port = 21;
// 秒数
private int defaultTimeoutSecond = 60;
private int connectTimeoutSecond = 30;
private int dataTimeoutSecond = 30;
// 秒
private int controlKeepAliveTimeout = 120;
private boolean isTextMode = false;
private String tranEncoding = "GB2312";
private FTPClient client;
public ApacheFtpUtil(String host, String username, String password) {
this(host, username, password, 21, 0);
}
public ApacheFtpUtil(String host, String username, String password, int port) {
this(host, username, password, port, 0);
}
public ApacheFtpUtil(String host, String username, String password, int port, int security) {
this.host = host;
this.port = port;
this.username = username;
this.password = password;
}
public void initClint() throws Exception {
// FTPSClient
client = new FTPClient();
// 每大约2分钟发一次noop,防止大文件传输导致的控制连接中断
client.setControlKeepAliveTimeout(controlKeepAliveTimeout);
// client.setListHiddenFiles(listHiddenFiles);
// FTPClientConfig config = new
// FTPClientConfig(FTPClientConfig.SYST_NT);
// config.setServerLanguageCode("zh");
// config.setUnparseableEntries(saveUnparseable);
// config.setDefaultDateFormatStr(defaultDateFormat);
// config.setRecentDateFormatStr(recentDateFormat);
// client.configure(config);
// 设置默认超时
client.setDefaultTimeout(defaultTimeoutSecond * 1000);
// 连接超时
// client.setConnectTimeout(connectTimeoutSecond * 1000);
// 设置数据超时
// client.setDataTimeout(dataTimeoutSecond * 1000);
/*
* socket超时 设置一个命令执行后最大等待Server反馈的时间. 如果对方连接状态60秒没有收到数据的话强制断开客户端
*/
// client.setSoTimeout(60 * 1000);
// client.setBufferSize(1024);
// 连接到远程的FTP服务器.
try {
client.connect(this.host, this.port);
} catch (Exception e) {
this.destory();
log.error("连接服务器失败,host:{}, port:{}", this.host, this.port);
throw e;
}
int reply = client.getReplyCode(); // 获得返回的代码,来判断连接状态
if (!FTPReply.isPositiveCompletion(reply)) {
this.destory();
// 连接错误
throw new Exception("Can‘t Connect to :" + host);
}
// 登录
boolean flag = client.login(this.username, this.password);
if (flag == false) {
this.destory();
throw new Exception("Invalid user/password");
}
try {
if (FTPReply.isPositiveCompletion(client.sendCommand("OPTS UTF8", "ON"))) {
// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码,否则就使用本地编码
tranEncoding = "UTF-8";
log.debug("FTP Server allow UTF8 encoding");
}
} catch (Exception e) {
log.error("ftp server opts utf8 error,{}", e.getMessage());
}
log.info("use encoding {}", tranEncoding);
client.setControlEncoding(tranEncoding); // 中文支持
// 设置传送模式
if (isTextMode) {
client.setFileType(FTP.ASCII_FILE_TYPE);
} else {
client.setFileType(FTP.BINARY_FILE_TYPE);
}
/*
* PORT中文称为主动模式,工作的原理:
* FTP客户端连接到FTP服务器的21端口,发送用户名和密码登录,登录成功后要list列表或者读取数据时,
* 客户端随机开放一个端口(1024以上),发送 PORT命令到FTP服务器,告诉服务器客户端采用主动模式并开放端口;
* FTP服务器收到PORT主动模式命令和端口号后,通过服务器的20端口和客户端开放的端口连接,发送数据.
* 主动模式需要客户端必须开放端口给服务器,很多客户端都是在防火墙内,开放端口给FTP服务器访问比较困难。
*/
// client.enterLocalActiveMode(); //主动模式
/*
* PASV是Passive的缩写,中文成为被动模式.
* 工作原理:FTP客户端连接到FTP服务器的21端口,发送用户名和密码登录,登录成功后要list列表或者读取数据时,
* 发送PASV命令到FTP服务器, 服务器在本地随机开放一个端口(1024以上),然后把开放的端口告诉客户端,
* 客户端再连接到服务器开放的端口进行数据传输. 被动模式只需要服务器端开放端口给客户端连接就行了。
*/
client.enterLocalPassiveMode();
// client.setUseEPSVwithIPv4(useEpsvWithIPv4);
log.debug("==========初始化FTP连接成功===========");
}
public void destory() {
if (client == null) {
return;
}
try {
client.logout();
} catch (IOException e) {
e.printStackTrace();
}
try {
client.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
client = null;
}
public void changeRemoteDir(String newPath) throws RuntimeException {
// 切换路径[相对路径和绝对路径都可]
if (StringUtils.isBlank(newPath)) {
return;
}
try {
boolean flag = client.changeWorkingDirectory(new String(newPath.getBytes(tranEncoding), "ISO-8859-1"));
log.debug("change working directory to {}, status:{}", newPath, flag);
} catch (IOException e) {
throw new RuntimeException("切换路径失败:" + newPath + "; " + e.getMessage());
}
}
/**
* 下载文件
*/
public void download(String remoteFile, String localOutFile) throws RuntimeException {
FileOutputStream outstream = null;
// 下载文件
try {
log.debug("开始下载文件 {}", remoteFile);
outstream = new FileOutputStream(new File(localOutFile));
/*
* 这个方法的意思就是每次数据连接之前,ftp client告诉ftp server开通一个端口来传输数据. 因为ftp
* server可能每次开启不同的端口来传输数据,但是在linux上,由于安全限制,可能某些端口没有开启,所以就出现阻塞
*/
client.enterLocalPassiveMode();
client.setFileType(FTP.BINARY_FILE_TYPE);
/*
* FTP协议里面,规定文件名编码为iso-8859-1,所以目录名或文件名需要转码 retrieveFile的第一个参数需要是
* ISO-8859-1 编码
*/
client.retrieveFile(new String(remoteFile.getBytes(tranEncoding), "ISO-8859-1"), outstream);
} catch (IOException e) {
throw new RuntimeException("下载文件失败:" + remoteFile + "; " + e.getMessage());
} finally {
if (outstream != null) {
try {
outstream.flush();
outstream.close();
} catch (IOException e) {
}
}
}
log.debug("下载文件 {} 完成", remoteFile);
}
}
原文地址:http://blog.51cto.com/dengshuangfu/2130277
时间: 2024-11-11 03:46:21