分 本地同步到 FTP 和 FTP同步到本地 两种
只依赖FTPClient 即可,其他部分替代即可。
具体使用看main方法
import cn.hutool.core.io.FileUtil;
import org.apache.commons.io.FileUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 描述:
* FTP 同步工具
* @Auther: huanggp
* @Date: 2020/7/9
* @Copyright: 2020 www.***.com Inc. All rights reserved.
* @version: 1.0.0
*/
public class FTPFileSyncTool {
private static Logger logger = LoggerFactory.getLogger(FTPFileSyncTool.class);
private FTPClient ftpClient;
private boolean isDelSourceFile = false;
public FTPFileSyncTool(boolean isDelSourceFile) {
this.isDelSourceFile = isDelSourceFile;
ftpClient = new FTPClient();
}
/**
* 同步本地文件到FTP
* @param ftp FTP配置信息
* @param isDelSourceFile 是否删除源文件
*/
public static int syncToFTP(FTP ftp ,boolean isDelSourceFile){
int suc = 0;
FTPFileSyncTool fd = new FTPFileSyncTool(isDelSourceFile);
fd.connect(ftp);
try {
suc = fd.uploadDir(new File(ftp.getLocalFolder()), ftp.getFtpFolder());
} catch (Exception e) {
logger.error("同步失败,失败原因是:{}",e.getMessage());
}
// 释放
fd.disconnect();
return suc;
}
/**
* 同步FTP文件到本地
*
* @param ftp {
* ftpFolder: 一定要以/ 分隔符结尾
* localFolder: 一定要以/ 分隔符结尾
* }
*/
public static void syncToLocal(FTP ftp , boolean isDelSourceFile) {
FTPFileSyncTool fd = new FTPFileSyncTool(isDelSourceFile);
//链接
fd.connect(ftp);
// 同步
fd.downDir(ftp.getFtpFolder(), ftp.getLocalFolder());
// 释放
fd.disconnect();
}
private int uploadDir(File file , String ftpPathPrefix) throws Exception{
int suc = 0;
if(file.isDirectory()){
ftpClient.makeDirectory(ftpPathPrefix + file.getName());
ftpClient.changeWorkingDirectory(ftpPathPrefix + file.getName());
String[] files = file.list();
if((files == null || files.length == 0) && isDelSourceFile) {
FileUtils.deleteDirectory(file);
}
for (int i = 0; i < files.length; i++) {
File file1 = new File(file.getPath()+"\\"+files[i] );
if(file1.isDirectory()){
suc += uploadDir(file1,"");
ftpClient.changeToParentDirectory();
}else{
uploadFile(new File(file.getPath() + "\\" + files[i]));
suc ++;
}
}
}else{
uploadFile(file);
suc ++;
}
return suc;
}
private void uploadFile(File file) throws IOException {
FileInputStream input = new FileInputStream(file);
logger.info("准备上传文件:{}" , file.getPath());
ftpClient.storeFile(file.getName(), input);
input.close();
logger.info("上传文件完毕,准备删除文件:{} , 是否删除:{}" , file.getPath() ,isDelSourceFile);
if(isDelSourceFile){
FileUtil.del(file);
}
}
/**
* 功能说明:通过递归实现ftp目录文件与本地文件同步更新
*/
private void downDir(String ftpfilepath, String localpath) {
try {
FTPFile[] ftpFiles = ftpClient.listFiles(ftpfilepath);
// 得到当前ftp目录下的文件列表
if (ftpFiles != null) {
for (FTPFile ftpFile : ftpFiles) {
String localfilepath = localpath + ftpFile.getName();
File localFile = new File(localfilepath);
// 根据ftp文件生成相应本地文件
Date fflastModifiedDate = ftpFile.getTimestamp().getTime();
// 获取ftp文件最后修改时间
Date localLastModifiedDate = new Date(localFile
.lastModified());
// 获取本地文件的最后修改时间
int lastUpdateTimeByLocalFile = localLastModifiedDate
.compareTo(fflastModifiedDate);
// lastUpdateTimeByLocalFile=0,两文件最后修改时间相同;lastUpdateTimeByLocalFile<0,本地文件的最后修改时间早于ftp文件最后修改时间;lastUpdateTimeByLocalFile>0,则相反
if (ftpFile.isDirectory()) {
// 如果是目录
localFile.mkdir();
// 如果本地文件夹不存在就创建
String ftpfp = ftpfilepath + ftpFile.getName() + "/";
// 转到ftp文件夹目录下
String localfp = localfilepath + File.separator;
// 转到本地文件夹目录下
this.downDir(ftpfp, localfp);
// 递归调用
} else if (ftpFile.isFile()) {
// 如果是文件
File lFile = new File(localpath);
lFile.mkdirs();
// 如果文件所在的文件夹不存在就创建
if (!lFile.exists()) {
return;
}
if (ftpFile.getSize() != localFile.length() || lastUpdateTimeByLocalFile < 0) {
// 如果ftp文件和本地文件大小不一样或者本地文件不存在或者ftp文件有更新,就进行创建、覆盖
String filepath = ftpfilepath + ftpFile.getName();
// 目标ftp文件下载路径
FileOutputStream fos = new FileOutputStream(
localFile);
boolean downFileResult;
try {
downFileResult = ftpClient.retrieveFile(new String(
filepath.getBytes("UTF-8"),
"ISO-8859-1"), fos);
// 从FTP服务器上取回一个文件
} catch (Exception e) {
downFileResult = false;
logger.error("下载文件异常:{}", e);
}
String name = ftpFile.getName();
String dir = localpath;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String time = sdf.format(localFile.lastModified());
if (downFileResult && isDelSourceFile) {
ftpClient.deleteFile(filepath);
logger.debug("download file succussful: fileName: {} , localpath: {} time:{} ", name, dir, time);
} else {
logger.info("download file failed: fileName: {} , localpath: {} time:{} ", name, dir, time);
}
fos.flush();
fos.close();
} else {
// System.out.println("两个文件相同!");
}
}
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 连接ftp服务器
* @param ftp
*/
private void connect(FTP ftp) {
String hostip = ftp.getHost();
int port = ftp.getPort();
String username = ftp.getUsername();
String password = ftp.getPassword();
try {
ftpClient.connect(hostip, port);
// 连接服务器
ftpClient.login(username, password);
// 登录
// 检测是否连接成功
int reply = ftpClient.getReplyCode();
// 看返回的值是不是230,如果是,表示登陆成功
if (!FTPReply.isPositiveCompletion(reply)) {
// 返回的code>=200&&code<300return
ftpClient.disconnect();
// 关闭FTP连接
}
ftpClient.setControlEncoding("UTF-8");
// 设置字符编码
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
/**
* 一定要使用被动模式,否则 listFiles
* linux 会卡住
* windows 暂未发现
*/
ftpClient.enterLocalPassiveMode();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 释放链接
**/
private void disconnect() {
FTPClient client = ftpClient;
if (null != client && client.isConnected()) {
try {
client.logout();
client.disconnect();
} catch (IOException ex) {
logger.error("FTP释放链接时,发生异常,异常信息为:{}", ex.getMessage());
}
}
}
/**
* @param args
*/
public static void main(String[] args) {
final FTP ftp = new FTP();
ftp.setHost("localhost").
setPort(21).
setUsername("hgp").
setPassword("123456").
setFtpFolder("/root/").
setLocalFolder("D:\\ftp\\attachment\\");
FTPFileSyncTool.syncToFTP(ftp , true);
}
public static class FTP {
private String host;
private int port = 21;
private String username;
private String password;
/**
* 需要同步FTP的文件夹
*/
private String ftpFolder;
/**
* 同步到本地的文件夹
*/
private String localFolder;
public String getHost() {
return host;
}
public FTP setHost(String host) {
this.host = host;
return this;
}
public int getPort() {
return port;
}
public FTP setPort(int port) {
this.port = port;
return this;
}
public String getUsername() {
return username;
}
public FTP setUsername(String username) {
this.username = username;
return this;
}
public String getPassword() {
return password;
}
public FTP setPassword(String password) {
this.password = password;
return this;
}
public String getFtpFolder() {
return ftpFolder;
}
public FTP setFtpFolder(String ftpFolder) {
this.ftpFolder = ftpFolder;
return this;
}
public String getLocalFolder() {
return localFolder;
}
public FTP setLocalFolder(String localFolder) {
this.localFolder = localFolder;
return this;
}
}
}