本文共 6240 字,大约阅读时间需要 20 分钟。
使用 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); }}
转载于:https://blog.51cto.com/dengshuangfu/2130277