前段时间做了个任务,是公司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(); } }可以发现,我没有做断点续传的功能,这也是程序中的一个缺陷,我会尽快完善,谢谢,发现代码有可改进之处,欢迎指出。