文章介绍
本人新手第一次发博客,且经验也不是很丰富,可能还存在很多问题,希望有大佬能指导下,我这篇文章主要还是给个参考
话不多说,掏出我那长长的。。。
第一步:连接ftp服务器
连接这里要注意的是设置ftpclient超时属性一定要在connect(连接)前设置好,否则不会生效
其中阻塞问题是设置ftpClient.setSoTimeout(1 * 60 * 1000);这个属性是超时处理,且不是传输过程的总超时时间,而是每次的超时时间。
总之,setSoTimeout()
用于设置从 Socket 的输入流中读取数据时每次陷入阻塞过程的超时时间。
/**
* 初始化ftp服务器
*/
public void initFtpClient() {
ftpClient.setControlEncoding("utf-8");
try {
System.out.println("connecting...ftp服务器:" + this.hostname + ":" + this.port);
ftpClient.setDefaultTimeout(10 * 60 * 1000);
ftpClient.setConnectTimeout(10 * 60 * 1000);
ftpClient.setDataTimeout(10 * 60 * 1000);
ftpClient.connect(hostname, port); //连接ftp服务器
//设置FTP属性
ftpClient.enterLocalPassiveMode();//被动模式
// socket连接,设置socket连接超时时间(单位:ms)
ftpClient.setSoTimeout(1 * 60 * 1000);
ftpClient.login(username, password); //登录ftp服务器
ftpClient.setBufferSize(1024 * 1024 * 32);
ftpClient.setControlKeepAliveTimeout(3000);
ftpClient.setControlKeepAliveReplyTimeout(3000);
//ftpClient.setKeepAlive(true);
ftpClient.setRemoteVerificationEnabled(false);
int replyCode = ftpClient.getReplyCode(); //是否成功登录服务器
if (!FTPReply.isPositiveCompletion(replyCode)) {
System.out.println("connect failed失败...ftp服务器:" + this.hostname + ":" + this.port);
} else {
System.out.println("connect successful成功...ftp服务器:" + this.hostname + ":" + this.port);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
第二步:下载ftp文件至本地
为什么我在下载这里加连接ftp,而不在外部直接调用,就当你下载多个文件(不考虑说下载整个文件夹)时,我认为的是它每次连接之后用完,不是有个关闭连接吗,然后它就会一个在寻求连接,一直在哪等待,程序就不走了,还有就是设置被动模式ftpClient.enterLocalPassiveMode(); 这个的作用是针对于防火墙以及Linux系统部分(默认主动),因为它每次主动去拿,会被系统所拦截掉,然后需要等待它给。造成程序假死还有一个原因ftpClient.retrieveFile(ff.getName(), os);这个方法,你在连接的时候设置我上面的那些个属性就不会有问题,也不会卡死,还有就是因为ftp连接那个方法是开启一个线程的,然后你下载文件也是用同一个线程,然后就会阻塞,我这边只是设置了一些ftp属性,你也可以通过Thread类开另外一个线程来进行(与连接方法放开,单独跑一个)
/**
* 从FTP服务器下载文件
* <p>
* ftpPath FTP服务器中文件所在路径
*
* @param remotePath FTP服务器上的相对路径
* @param fileName 要下载的文件名
* @Param localPath下载后保存到本地的路径
*/
public static boolean downFile(String remotePath, String fileName, String localPath) {
ftp.initFtpClient();
boolean success = false;
try {
ftpClient.changeWorkingDirectory(remotePath);//转移到FTP服务器目录
ftpClient.enterLocalPassiveMode();
FTPFile[] fs = ftpClient.listFiles();
for (FTPFile ff : fs) {
if (ff.getName().equals(fileName)) {
File localFile = new File(localPath + "/" + ff.getName());
OutputStream os = new FileOutputStream(localFile);
ftpClient.retrieveFile(ff.getName(), os);
os.close();
success = true;
}
}
ftpClient.logout();
} catch (IOException e) {
System.err.println("【防止阻塞】IOE错误 程序继续。。。");
} finally {
if (ftpClient.isConnected()) {
try {
ftpClient.disconnect();
} catch (IOException ioe) {
}
}
}
return success;
}
第三步:测试
FTPFile[] ftplist = ftp.ftpFileList();
List<File> filelist = ftp.localFileList();
try {
for (int j = 0; j < ftplist.length; j++) {
boolean flag = true;
for (int i = 0; i < filelist.size(); i++) {
if (ftplist[j].getName().equals(filelist.get(i).getName())) {
if (ftplist[j].getSize() == filelist.get(i).length()) {
flag = false;
}
}
}
if (flag) {
booleanb=downFile("/gxgplay",ftplist[j].getName(),"D:\\ftpTest");
if (b) {
System.out.println("成功完成文件下载:" + ftplist[j].getName());
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
总结:
setConnectTimeout()
用于设置终端 Socket 与 FTP 服务器建立连接这个过程的超时时间。setDefaultTimeout()
用于设置终端的传输控制命令的 Socket 的 SoTimeout,即针对传输控制命令的 Socket 的输入流做读取操作时每次陷入阻塞的超时时间。setSoTimeout()
作用跟上个方法一样,区别仅在于该方法设置的超时会覆盖掉上个方法设置的值。setDataTimeout()
用于设置终端的传输数据的 Socket 的 Sotimeout,即针对传输文件数据的 Socket 的输入流做读取操作时每次陷入阻塞的超时时间。setControlKeepAliveTimeout()
用于设置当处于传输数据过程中,按指定的时间阈值定期让传输控制命令的 Socket 发送一个无操作命令 NOOP 给服务器,让它 keep alive。setControlKeepAliveReplyTimeout()
:只有调用上个方法后,该方法才能生效,用于设置在传输数据这个过程中,暂时替换掉传输控制命令的 Socket 的 SoTimeout,传输过程结束恢复这个 Socket 原本的 SoTimeout。
以上是我的个人理解,修为甚浅,还请见谅,最后这个是无意看到的,希望对你有帮助!✈