본문 바로가기

기타

이클립스 Ant를 이용한 FTP 사용하기

1. 준비물

*이클립스 = 이클립스라 검색하여 다운받자

*commons-net-X.X.jar = http://commons.apache.org/net/download_net.cgi 다운받자


2. 준비하기

*이클립스 Window -> Preferences -> Ant -> Runtime -> Classpath항목에서

Ant Home Entries 클릭 후 Add External JARs... 클릭하여 commons-net-X.X.jar 를 추가

*프로젝트를 생성후 Bulid.xml 과 bulid.properties 파일 생성


3. 만들기

*bulid.properties


################################### ## FTP INFO ## ################################### FTP.SERVER = xxx.xxx.xxx.xxx FTP.PORT = 21 FTP.USERID = test FTP.PASSWD = 1234567890 FTP.PATH = / FTP.PATH.CLASS = /WEB-INF/classes/ ## /*.class , /test/*.class EXCLUDE.PATTERN = FTP_NOT_PATTERN BACKUP.PATH = D:/ant/backup/ ACCEPT.CLASS = .class, .xml ACCEPT.WEB = .jsp


위와 같이 설정하자.

*Bulid.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<?xml version="1.0" encoding="utf-8"?>
<project name="ftpUpload" default="all" basedir=".">
<property file="build.properties" />
<property name="build.dir" value="." />
<property name="output.class.dir" value="${build.dir}/build/classes" />
<property name="work.web.dir" value="${build.dir}/web" />
<target name="all">
<!--
<antcall target="download" />
<antcall target="delete" />
<antcall target="upload" />
-->
<antcall target="execute" />
</target>
<!--FTP Upload-->
<target name="upload">
<ftp server="${FTP.SERVER}" port="${FTP.PORT}" remotedir="${FTP.PATH}" userid="${FTP.USERID}" password="${FTP.PASSWD}" newer="true" timediffauto="true" passive="yes" binary="yes" depends="yes" verbose="yes" separator="/" serverLanguageCodeConfig="en" serverTimeZoneConfig="KORST-9">
<fileset dir="${output.class.dir}">
<include name="**/*.class" />
</fileset>
</ftp>
</target>
<!--FTP Download-->
<target name="download">
<ftp server="${FTP.SERVER}" port="${FTP.PORT}" remotedir="${FTP.PATH}" userid="${FTP.USERID}" password="${FTP.PASSWD}" newer="true" timediffauto="true" passive="yes" binary="yes" depends="yes" verbose="yes" separator="/" serverLanguageCodeConfig="en" serverTimeZoneConfig="KORST-9">
<fileset dir="${BACKUP.PATH}">
<include name="**/*.class" />
</fileset>
</ftp>
</target>
<!--FTP List-->
<target name="list">
<ftp server="${FTP.SERVER}" port="${FTP.PORT}" remotedir="${FTP.PATH}" userid="${FTP.USERID}" password="${FTP.PASSWD}" timediffauto="true" action="list" listing="D:/ant/ftp.list" passive="yes" binary="yes" depends="yes" verbose="yes" separator="/" serverLanguageCodeConfig="en" serverTimeZoneConfig="KORST-9">
<fileset dir="${BACKUP.PATH}">
<include name="**/*.class" />
</fileset>
</ftp>
</target>
<!--FTP Delete-->
<target name="delete">
<echo message="서버의 파일을 삭제 합니다." />
<ftp server="${FTP.SERVER}" port="${FTP.PORT}" remotedir="${FTP.PATH}" userid="${FTP.USERID}" password="${FTP.PASSWD}" action="del" passive="yes" binary="yes" depends="yes" verbose="yes" separator="/" serverTimeZoneConfig="KORST-9">
<fileset>
<include name="**/*.class" />
</fileset>
</ftp>
</target>
<!-- JAVA FTP -->
<target name="execute" >
<java classname="com.jang.test.FTPController" classpath="WebContent/WEB-INF/lib/commons-net-3.2.jar;build/classes;">
<arg file="." />
<arg value="build.properties" />
</java>
</target>
</project>


라고 입력하고 download, upload, deleted 를 실행해보자

모든 파일을 할때는 잘된다.

하지만 실행할때마다 모든파일을 업로드, 다운로드를 하기엔 쫌 그렇다.

변경파일만 해보자.

인터넷 찾아보니 newer="true" timediffauto="true" passive="yes" binary="yes" depends="yes" verbose="yes"

옵션주면 된다고 한다.

하지만 나는 윈도우서버 FTP를 이용하고 있었는데 잘동작하지 않았다.

그래서 execute를 만들었다.

execute는 이클립스 전용임으로 /bulid/classes와 WebContent가 있는 전제하에 만들었다.


4. FTP 업로드 JAVA로 만들기

package com.jang.test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

import com.jang.utils.DateUtils;
import com.jang.utils.FileUtils;
import com.jang.utils.StringUtils;

 

 

/************************************************************************
 * @ClassName     : FTPController         
 * @ClassDescription  : FTP 관련 클레스
 *                   
 * @MakeDate    : 2013-01-23        
 * @author      : Jang.S.H         
 *                   
 * @Copyright    : Media4th &amp; Company      
 ************************************************************************/
public class FTPController {
 private FileUtils FU;
 private FTPClient ftpClient;
 private String server;
 private String port;
 private String userPw;
 private String userId;
 private String backupPath;
 private String classRoot;
 private String uploadRoot;
 private String exPattern;
 
 private String acceptClass;
 private String acceptWeb;
 
 
 
 public static void main(String[] args) {
  if(args != null &amp;&amp; args.length == 2){
   
   //String path = "D:/web/workspace/JangUtils/build.properties";
   String path = args[0]+"\\"+args[1];
   FTPController main = new FTPController(path);
   
   try {
    main.init();
    main.run();
   } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
  
  //즉시 테스트 입니다.
//  String path = "D:/web/workspace/JangUtils/build.properties";
//  FTPController main = new FTPController(path);
//  
//  try {
//   main.init();
//   main.run();
//  } catch (Exception e) {
//   // TODO Auto-generated catch block
//   e.printStackTrace();
//  }
//  
  
 }
 
 public FTPController(String path){
  FU = FileUtils.getInstance();
  
  setting(path);
 }
 
 
 /**
  * @author Jang.S.H
  * @throws Exception
  * @description
  * FTP 접속 셋팅
  * Encoding : EUC-KR
  * Connection Check
  * Login Check
  */
 private void init() throws Exception {
  sys("init start");
  
  ftpClient = new FTPClient();
  ftpClient.setControlEncoding("EUC-KR");
  
  
  sys("Connect server:"+server +"\t Port:"+port);
  ftpClient.connect(server, Integer.parseInt(port));
   
  int reply = ftpClient.getReplyCode();
  
  //접속 체크
  if (!FTPReply.isPositiveCompletion(reply)) {
   sys("Connect Error Check server:"+server +"\tport:"+port);
   ftpClient.disconnect();
   
   throw new Exception();
  }

  //로그인 체크
  if(!ftpClient.login(userId, userPw)){
   sys("LOGIN Error Check userId:"+userId +"\t userPw:"+userPw);
   ftpClient.disconnect();
   
   throw new Exception();
  }
   
  ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
     ftpClient.setFileTransferMode(FTP.STREAM_TRANSFER_MODE);
  
     sys("init end");
 }
 
 
 /**
  * @author Jang.S.H
  * @description
  * FTP 기능 수행
  * LOCAL - FTP 간 파일비교
  * BACKUP
  * UPLOAD
  */
 private void run(){
  try {
   sys("run start");
   
   if(ftpClient.isConnected()){
    //로컬 추출
    HashMap&lt;String, File&gt; localClass = getLocalFiles(getClassPath(),acceptClass);
    //FTP 추출
    HashMap&lt;String, FTPFile&gt; ftpClass = getFtpFiles(classRoot, acceptClass);
    
    //리스트 추출 및 백업
    ArrayList&lt;String&gt; updateList = compareFileList(localClass, ftpClass, classRoot);
    
    //변경목록 업로드
    upload(localClass, updateList, classRoot);
    
    localClass.clear();
    ftpClass.clear();
    updateList.clear();
    
    //로컬 추출
    localClass = getLocalFiles(getWebRootPath(),acceptWeb);
    //FTP 추출
    ftpClass = getFtpFiles(uploadRoot, acceptWeb);
    
    //리스트 추출 및 백업
    updateList = compareFileList(localClass, ftpClass, uploadRoot);
    //변경목록 업로드
    upload(localClass, updateList, uploadRoot);
    
    localClass.clear();
    ftpClass.clear();
    updateList.clear();
    
    ftpClient.disconnect();
   }
   
   
   sys("run end");
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
 
 /**
  * @author Jang.S.H
  * @param path
  *  properties 파일 경로
  * @description
  * 프로퍼티 파일을 읽어와 셋팅하기
  */
 private void setting(String path){
  
  if(FU.isFile(path)){
   Properties conf = FU.readProperties(path);
   server = StringUtils.getProperty(conf, "FTP.SERVER");
   port = StringUtils.getProperty(conf, "FTP.PORT");
   userId = StringUtils.getProperty(conf, "FTP.USERID");
   userPw = StringUtils.getProperty(conf, "FTP.PASSWD");
   backupPath = StringUtils.getProperty(conf, "BACKUP.PATH");
   classRoot = StringUtils.getProperty(conf, "FTP.PATH.CLASS");
   uploadRoot = StringUtils.getProperty(conf, "FTP.PATH");
   exPattern = StringUtils.getProperty(conf, "EXCLUDE.PATTERN");
   acceptClass = StringUtils.getProperty(conf, "ACCEPT.CLASS");
   acceptWeb = StringUtils.getProperty(conf, "ACCEPT.WEB");
   
   
   sys("SETTING \t server:\t"+server);
   sys("SETTING \t port:\t"+port);
   sys("SETTING \t userId:\t"+userId);
   sys("SETTING \t userPw:\t"+userPw);
   sys("SETTING \t backupPath:\t"+backupPath);
   sys("SETTING \t classRoot:\t"+classRoot);
   sys("SETTING \t uploadRoot:\t"+uploadRoot);
  }else{
   sys("setting Error NOT FILE");
  }
 }
 
 
 /**
  * @author Jang.S.H
  * @param localMap
  *  LOCAL 파일정보
  * @param ftpMap
  *  FTP 파일정보
  * @param root
  *  FTP 파일 루트
  * @return
  *  변경파일 목록
  * @description
  * LOCAL - FTP 간 파일 비교후 변경파일 리스트 추출
  */
 private ArrayList&lt;String&gt; compareFileList(HashMap&lt;String, File&gt; localMap, HashMap&lt;String, FTPFile&gt; ftpMap, String root){
  ArrayList&lt;String&gt; returnArray = new ArrayList&lt;String&gt;();
  
  Set&lt;String&gt; set =  localMap.keySet();
  
  File f1 = null;
  FTPFile f2 = null;
  
  String backupLog = getBackupPath()+"loglog.txt";
  
  FU.setTextFile(backupLog, DateUtils.getNormalDate("yyyy-MM-dd hh:mm:ss"), false);
  for (String key : set) {
   f1 = localMap.get(key);
   if(ftpMap.containsKey(key)){
    f2 = ftpMap.get(key);
    
    if(f1.lastModified() &gt; f2.getTimestamp().getTimeInMillis() &amp;&amp; f1.length() != f2.getSize()){
     sys("Modify :\t"+f1.getAbsolutePath());
     
     backup(key, root);
     returnArray.add(key);
     
     FU.setTextFile(backupLog, f1.getAbsolutePath(), true);
    }
    
   }else{
    sys("INSERT :\t"+f1.getAbsolutePath());
    returnArray.add(key);
    FU.setTextFile(backupLog, f1.getAbsolutePath(), true);
   }
  }
  
  return returnArray;
 }
 
 /**
  * @author Jang.S.H
  * @param path
  *  root로 부터 상대경로
  * @param root
  *  root 경로
  * @description
  * 백업폴더에 FTP 전체경로 백업한다.
  * 전체경로 = root + path
  */
 private void backup(String path, String root) {
  try{
   
   File put_file = new File(getBackupPath()+root+path); // 저장시켰던 파일을 서버로 전송
   put_file.mkdirs();
   if(put_file.isDirectory()){
    put_file.delete();
    FileWriter fi = new FileWriter(put_file);
    fi.close();
   }
   
   FileOutputStream fos = new FileOutputStream(put_file);
   boolean ret = ftpClient.retrieveFile(root+path, fos);
   fos.close();
   
   if(ret){
    sys("BACKUP SUCCESS :\t"+root+path + "\t=&gt;\t" +put_file.getAbsolutePath() );
   }else{
    sys("BACKUP FAIL :\t"+root+path + "\t=&gt;\t" +put_file.getAbsolutePath());
   }
   
  }catch (Exception e) {
   sys("BACKUP Error :\t"+path);
   sys(e.toString());
  }
 }
 
 /**
  * @author Jang.S.H
  * @param localMap
  *  LOCAL 파일
  * @param list
  *  변경 리스트
  * @param root
  *  FTP ROOT
  * @description
  * 파일을 업로드 한다.
  */
 private void upload(HashMap&lt;String, File&gt; localMap, ArrayList&lt;String&gt; list, String root){
  
  try{
   File f = null;
   InputStream inputStream = null;
   boolean result = false;
   for(String s : list){
    String tmpString = (root+s).replace("//", "/");
    
    f = localMap.get(s);
    
       inputStream = new FileInputStream(f);
      
       int t = tmpString.lastIndexOf("/");
       ftpClient.makeDirectory(tmpString.substring(0,t));
      
       result = ftpClient.storeFile(tmpString, inputStream);
      
       if(result){
        sys("UPLOAD : \t"+tmpString);
       }else{
        sys("UPLOAD FAIL : \t"+tmpString);
       }
      
   }
   inputStream.close();
  }catch (Exception e) {
   // TODO: handle exception
  }
  
 }
 
 /**
  * @author Jang.S.H
  * @return
  * @description
  * 이클립스 기준 Class파일의 위치를 리턴.
  * {HOME}/bulid/classes/
  */
 private String getClassPath(){
  return this.getClass().getResource("/").getPath().substring(1);
 }
 
 /**
  * @author Jang.S.H
  * @return
  * @description
  * 이클립스 기준 WebContent위치를 리턴
  * {HOME}/WebContent/
  */
 private String getWebRootPath(){
  String path = getClassPath();
  int lastIndex = path.lastIndexOf("/");
  path = path.substring(0,lastIndex);
  lastIndex = path.lastIndexOf("/");
  path = path.substring(0,lastIndex);
  lastIndex = path.lastIndexOf("/");
  path = path.substring(0,lastIndex);
  path += "/WebContent/";
  
  return path;
  }
 
 private String getBackupPath(){
  return backupPath;
 }
 
 /**
  * @author Jang.S.H
  * @param path
  *  검색 경로
  * @param type
  *  검색 확장자
  * @return
  * @throws Exception
  * @description
  * key : 검색경로로 부터의 경로
  * value: 파일정보
  */
 private HashMap&lt;String, FTPFile&gt; getFtpFiles( String path, String type) throws Exception{
  HashMap&lt;String, FTPFile&gt; returnMap = new HashMap&lt;String, FTPFile&gt;();
  
  getFtpFileList(returnMap, path, path, type);
  
  return returnMap;
 }
 
 private void getFtpFileList(HashMap&lt;String, FTPFile&gt; map, String rootPath, String path, String type) throws IOException {
  FTPFile[] files = ftpClient.listFiles(path);
    
     for(FTPFile f: files){
      String filepath = path+f.getName();
      
      if(f.isDirectory()){
       getFtpFileList(map, rootPath, filepath+"/", type);
      }else if(f.isFile() &amp;&amp; (type.indexOf( FU.lastCut(f.getName(), ".") ) &gt;= 0)){
       map.put(filepath.replace(rootPath, "/"), f);
       //sys(filepath.replace(rootPath, "/"));
      }
     }
 }
 
 
 /**
  * @author Jang.S.H
  * @param path
  *  검색 경로
  * @param type
  *  검색 확장자
  * @return
  * @description
  *  key : 검색경로로 부터의 경로
  * value: 파일정보
  *
  */
 private HashMap&lt;String, File&gt; getLocalFiles(String path, String type){
  HashMap&lt;String, File&gt; returnMap = new HashMap&lt;String, File&gt;();
  
  ArrayList&lt;String&gt; array = FU.getDirectoryFileList(path, type);
  String[] arrAccept = exPattern.split(",");
  for (int i = 0; i &lt; array.size(); i++) {
   File f = new File(array.get(i));
   
   String filepath = "/"+array.get(i).replaceAll("\\\\", "/").replaceAll(path, "").replaceAll("//", "/");
   
   //sys(filepath + "___"+ f.length()+"______"+f.lastModified());
   
   boolean chk = isUrlPatternProc( arrAccept, filepath);
   //sys("TEST_" + chk+"_"+filepath+"_"+arrAccept[0]);
   if(!chk){
    returnMap.put(filepath, f);
   }else{
    
   }
  }
  
  return returnMap;
 }
 
 /**
  * @author Jang.S.H
  * @param arrPattern
  * @param value
  * @return
  * @description
  * URL 패턴을 체크해서 패턴에 있는지 없는지 체크
  */
 private boolean isUrlPatternProc(String[] arrPattern, String value){
  if(arrPattern == null || value == null) return false;
  
  Pattern p = null;
  Matcher m = null;
  for(String s: arrPattern){
   
   s = s.trim().replace("*", "[-a-zA-Z0-9+&amp;@#%?=~_|!:,.;]*");
   
   p = Pattern.compile(s.trim());
   m = p.matcher(value);
   if(m.find()){
    return true;
   }
  }
  return false;
 }
 
 /**
  * @author Jang.S.H
  * @param s
  * @description
  * 로그 출력
  */
 private void sys(String s){
  System.out.println("FTP LOG:\t"+s);
 }
}


 



위와 같이 만들자.

동작원리는 다음과 같다.

*LOCAL에 있는 파일들을 체크한다.

*FTP에 있는 파일들을 체크한다.

*LOCAL && FTP 를 비교후 날짜, 크기 변경된 파일들의 목록을 생성한다.

*변경파일을 BACKUP 경로에 다운받는다.

*변경파일을 업로드 한다.

*끝.


참 FileUtils는 파일 목록 긁어오기와 프로퍼티 파일 읽기 로그파일 만들기 정도 사용했는데.

이런건 인터넷쳐보면 금방메소드 만들수 있으니 알아서 하길 바란다.

동작 중 에러나 버그가 날 수도 있다.

안된다고 만든사람 욕하지말고 참고하고 자신이 직접 커스텀하거나 참고해서 새로 만들도록 하자.

노력이 있어야 발전이 있다.

출처 :http://m4nc.tistory.com/16