前言
首先了解ftp/sftp,这两个都是文件传输的协议,用于大文件的传输;ftp/sftp是客户端和服务端组成,两个端互相建立连接之后,可以上传下载文件。ftp与sftp主要的区别就是安全性上,sftp传输过程中会对内容进行加密,会更加安全,相对的效率会稍差些。
公司有个需求,编写一个任务,从机器A拉取文件或目录到机器B。如果配置了文件参数,那么拉取对应的文件,如果没有配置,将所有的文件拉取到B机器。
思路
大概的想了下,感觉比较简单,存在参数,下载对应文件到另一台机器;不存在参数,下载所有。仔细考虑了一下,发现还是有些东西的;
问题
- 首先存在参数,那么是否存在这个文件,不存在怎么处理?
- 转存文件时,是先下载文件到本地,再上传;还是说有其他方法?
- 转存所有文件,如何获得某个目录下所有文件?获得到文件后,是不是需要按照原来目录的形式上传?
- 机器B已经存在了文件,怎么进行处理?
解答
- 不存在文件,提示错误信息,并打印好日志
- 为了效率,直接从机器A得到文件流,然后和机器B建立连接,上传文件流
- 搜索了一下相关文件,没有发现可用的API;所以需要递归得到文件及文件所属目录;上传是按照源目录结构上传
- 已经存在的需要比对时间,进行处理
到这里,基本思路已经通畅;就可以进行编码了。
上干货
ftp使用的jar是 it.sauronsoftware.ftp4j sftp使用的jar是 com.jcraft.jsch
获得某个目录所有文件
下载所有文件思路是:从机器A的某个目录往下cd,遇到文件停止,遇到目录就继续往下。从而获得所有的文件绝对地址,组装为一个列表;然后遍历这个列表获得文件,逐个上传。
获得所有路径方法
/**
* 获得目录下,所有的文件路径
* @return
*/
public static List<String> getAllFile(String host, int port, String username, String password, String proxyHost, Integer proxyPort, String path, Boolean hasProxy) {
log.info(LogFormat.formatMsg("FtpUtil.getAllFile.start", "", "host=" + host + ",port=" + port + ",username=" + username +
",password=" + password + ",proxyHost=" + proxyHost + ",proxyPort=" + proxyPort + ",path=" + path));
FTPClient client = null;
List<String> fileList = new ArrayList<>();
try {
client = getFtpConnection(host, port, username, password, proxyHost, proxyPort, hasProxy);
fileList = addList(fileList, client, path);
} catch (Exception e) {
log.info(LogFormat.formatMsg("FtpUtil.getAllFile.error", "", "e=" + e.getMessage()));
} finally {
client = null;
}
return fileList;
}
递归获得目录 下所有文件路径
/**
* 递归获得目录 下所有文件路径
* @return
*/
public static List<String> addList(List<String> list, FTPClient client, String path) {
log.info(LogFormat.formatMsg("FtpUtil.addList.start", "", "path=" + path));
try {
if (path != null) {
client.changeDirectory(path);
}
path = client.currentDirectory();
FTPFile[] fileList = client.list();
if (fileList.length == 0) {
log.info(LogFormat.formatMsg("FtpUtil.getAllFile", "", "length is 0,return"));
return list;
} else {
for (FTPFile ftpFile : fileList) {
String fileOrDirName = ftpFile.getName();
String dir = path + "/" + fileOrDirName;
int type = ftpFile.getType();
if (type == FTPFile.TYPE_DIRECTORY) {
//当前是目录,进入下一层
log.info(LogFormat.formatMsg("FtpUtil.getAllFile", "", "ftpFile type is dir"));
addList(list, client, dir);
} else if (type == FTPFile.TYPE_FILE) {
//当前是文件,放入list
log.info(LogFormat.formatMsg("FtpUtil.getAllFile", "", "ftpFile type is file"));
list.add(dir);
} else {
log.info(LogFormat.formatMsg("FtpUtil.addList", "ftpType=" + type, "dir=" + dir));
}
}
}
} catch (Exception e) {
log.info(LogFormat.formatMsg("FtpUtil.addList", "", "e=" + e));
}
log.info(LogFormat.formatMsg("FtpUtil.addList.end", "", "list=" + JSON.toJSONString(list)));
return list;
}
建立ftp连接
private static FTPClient getFtpConnection(String host, int port,
String username, String password, String proxyHost, Integer proxyPort, Boolean hasProxy) throws Exception {
FTPClient client = new FTPClient();
client.connect(host, port);
client.login(username, password);
client.setPassive(true);
client.setType(FTPClient.TYPE_AUTO);
if (hasProxy) {
//设置代理 开始 使用的是squid正向代理
FTPProxyConnector type = new FTPProxyConnector(proxyHost, proxyPort);
client.setConnector(type);
}
//设置代理结束
return client;
}