前段时间做了个任务,是公司liunx机器上有个公司静态网站的文件夹,因为不定期的修改,修改完之后要同步到FTP服务器上,之前一直是手动使用FTP工具来同步,我的任务是开发一个能够同步静态网站的action,集成到ETL工具中,然后每天会自动运行这个action,这样就避免手动同步了。
之前没有做过FTP上传,百度之,做FTP上传有两个类库,一个sun的FtpClient,不过sun是不推荐使用这个类库的,而且引入的时候要指定rule,另一个是Apache的FTPClient,我先使用了sun的,出现了一些问题,没有找到解决方案,本文主要说明的是使用Apache的工具类,关于sun的FtpClient,会在下一篇文章中说明。
其实主要就是干4个事情:
1. 初始化参数
2. 连接ftp
3. 拷贝文件,有可能是递归,因为文件夹下包含目录
4. 断开ftp连接
每次同步只是同步更新文件,所以我把同步时间记录在一个文件里,放在本地,上传文件的时候判断该文件的更新时间是否大于上次的同步时间。
还有就是FTPClient的storeFile()方法,需要两个参数,一个是文件名,另一个是输入流,这样我就无法控制它的缓冲区大小,拷入源码追踪了一个,它的缓冲区字节是在Utils中定义的,默认是1024,我给它改成了1024 × 64的,然后重新编译回去。
还有一个方法是storeFileStream()方法,它会返回一个OutputStream,不过如果该文件不存在的话,返回的是null,我没有找到创建文件的方式,很遗憾。
下面贴代码,主要看copyDirectory方法。
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import org.apache.commons.net.ftp.FTPClient;
/**
* 向ftp同步静态网站(ftp上传)
* @author gaoshuang
*
*/
public class SynchronizeWebsiteAction implements IETLAction {
/**
* 同步文件计数
*/
private int num;
/**
* 本地文件路径
*/
private String localPath;
/**
* ftp地址
*/
private String ipAdress;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* ftp文件路径
*/
private String ftpPath;
/**
* 上次更新时间
*/
private long lastUpdate;
/**
* ftp连接
*/
private FTPClient ftp;
public void addAdapter(String name, int type, ISourceAdapter adapter,
String description) {
}
/**
* 入口方法
*/
public void execute(String params, ETLContext context) throws Exception {
init(params);
connect();
copyDirectory(localPath, ftpPath);
disConnect();
// 记录本次更新时间
OutputStream os = new FileOutputStream(localPath + "/lastUpdate.txt");
os.write((System.currentTimeMillis() + "").getBytes());
}
/**
* 初始化
* @param params action参数
* @throws NumberFormatException
* @throws IOException
*/
private void init(String params) throws NumberFormatException, IOException {
String[] paths = params.split(",");
localPath = paths[0];
String[] ftpInfo = paths[1].split(";");
ipAdress = ftpInfo[0];
username = ftpInfo[1];
password = ftpInfo[2];
ftpPath = ftpInfo[3];
lastUpdate = getLastUpdate();
}
/**
* 得到上次更新时间
* @return
* @throws NumberFormatException
* @throws IOException
*/
private long getLastUpdate() throws NumberFormatException, IOException {
File file = new File(localPath + "/lastUpdate.txt");
long time = 0;
if(file.exists()) {
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
time = Long.parseLong(br.readLine());
}
return time;
}
/**
* 拷贝目录
* @param srcDirectoryPath 源
* @param destDirectoryPath 目标
* @throws IOException
*/
public void copyDirectory(String srcDirectoryPath, String destDirectoryPath) throws IOException {
// 创建不存在的目录
reConnect();
ftp.makeDirectory(destDirectoryPath);
File src = new File(srcDirectoryPath);
File[] allFile = src.listFiles(); // 取得当前文件夹下的所有文件,包括目录
String srcName = "";
// 拷貝文件
for (int currentFile = 0; currentFile < allFile.length; currentFile++) {
if (!allFile[currentFile].isDirectory()) {
// 如果是文件是采用处理文件的方式
srcName = allFile[currentFile].toString();
Logger.debug("开始上传文件到" + destDirectoryPath + "/" + allFile[currentFile].getName());
copyFile(srcName, destDirectoryPath, allFile[currentFile].getName());
} else {
// 如果是目录就采用递归处理
Logger.debug(destDirectoryPath + "/" + allFile[currentFile].getName().toString());
copyDirectory(allFile[currentFile].getPath().toString(), destDirectoryPath + "/" + allFile[currentFile].getName().toString());
}
}
}
/**
* 连接失去的时候重新连接
* @throws IOException
*/
private void reConnect() throws IOException {
while(!ftp.isConnected()) {
connect();
}
}
/**
* 拷贝文件
* @param src
* @param dest
* @throws IOException
*/
private void copyFile(String src, String dirPath, String fileName) throws IOException{
File file = new File(src);
if(file.lastModified() > lastUpdate && file.length() != 0) {
reConnect();
InputStream is = new FileInputStream(file);
ftp.setControlEncoding("GBK");
ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
ftp.changeWorkingDirectory(dirPath);
ftp.storeFile(fileName, is);
is.close();
Logger.debug("上传文件到" + "" + dirPath + "/" + fileName + "成功,这是第" + ++num + "个");
}
}
/**
* 连接ftp服务器
* @throws IOException
*/
private void connect() throws IOException {
ftp = new FTPClient();
ftp.connect(ipAdress);
ftp.login(username, password);
}
/**
* 关闭连接
* @param ftp
* @throws IOException
*/
private void disConnect() throws IOException {
ftp.disconnect();
}
}
可以发现,我没有做断点续传的功能,这也是程序中的一个缺陷,我会尽快完善,谢谢,发现代码有可改进之处,欢迎指出。