FTP를 통해 파일 다운로드
FTP 에서 파일을 내려받아야하는 기능을 추가할 일이 생겼다.
기존 프레임워크에 있던 SFTP 용 java파일을 활용해보려고 했지만 SFTP에 사용하는 라이브러리와 FTP에 사용하는 라이브러리가 달라 기존 파일은 사용하지 못하겠다는 판단을 내리고 새로 만들게 되었다.
SFTP에서 사용하는 라이브러리는 common-vfs2 였고
FTP에서 사용하는 라이브러리는 commons-net 이었다.
https://commons.apache.org/proper/commons-net/download_net.cgi
Apache Commons Net – Download Apache Commons Net
Download Apache Commons Net Using a Mirror We recommend you use a mirror to download our release builds, but you must verify the integrity of the downloaded files using signatures downloaded from our main distribution directories. Recent releases (48 hours
commons.apache.org
commons-net 라이브러리는 아파치 공식 사이트에서 다운로드 가능하다.
https://summer-cat93.tistory.com/79
JAVA 파일 업로드, 다운로드 예제
Java 파일 업로드와 다운로드 코드 예제입니다. io file copy FTP httpClient, multiparts copy io file 패키지의 copy 방식으로 파일 업로드, 다운로드 하는 코드 예제 Upload import java.io.File; import java.io.FileInputStream
summer-cat93.tistory.com
https://202psj.tistory.com/1509
자바개발 FTP 관련
================================= ================================= ================================= 자바 FTP 컴포넌트 : [JAVA] 자바로 FTP 클라이언트 프로그램 작성하기 JAVA & WebPrograming 블로그 | 슬레이어 http://blog.naver.c
202psj.tistory.com
위 두 블로그를 참고 했다.
package smartsuite.app.common.ftp;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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 org.springframework.beans.factory.annotation.Value;
public class FtpClient {
private static final Log LOG = LogFactory.getLog(SFtpClient.class);
@Value ("#{ftp['ftp.hostname']}")
String hostname;
@Value ("#{ftp['ftp.port']}")
int port;
@Value ("#{ftp['ftp.username']}")
String username;
@Value ("#{ftp['ftp.password']}")
String password;
public String getHostname() {
return hostname;
}
public void setHostname(String hostname) {
this.hostname = hostname;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Map <String, Object> download(String localFilePath, String remoteFilePath, String fileName) {
FTPClient ftpClient = new FTPClient();
Map <String, Object> result = new HashMap<String, Object>();
boolean resultSts = true;
try {
ftpClient.connect(this.hostname, this.port);
int reply = ftpClient.getReplyCode();
if(!FTPReply.isPositiveCompletion(reply)) {
System.err.println("연결실패");
resultSts = false;
}
boolean loginSts = ftpClient.login(this.username, this.password);
if(!loginSts) {
System.err.println("로그인실패");
resultSts = false;
}
ftpClient.enterLocalPassiveMode();
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
// 폴더 생성
File folder = new File(localFilePath);
if(!folder.exists()) {
folder.mkdirs();
}
File localPath = new File(localFilePath+"\\"+fileName);
OutputStream outputStream = new FileOutputStream(localPath);
boolean downloadSts = ftpClient.retrieveFile(remoteFilePath, outputStream);
if(!downloadSts) {
System.err.println("다운로드실패");
resultSts = false;
}
FTPFile[] files = ftpClient.listFiles(remoteFilePath);
if (files.length > 0) {
long fileSize = files[0].getSize();
result.put("fileSize", fileSize);
System.out.println("파일 크기: " + fileSize + " bytes");
} else {
System.err.println("파일을 찾을 수 없습니다.");
resultSts = false;
}
outputStream.close();
ftpClient.logout();
} catch (Exception e) {
System.out.println(e);
result.put("resultSts", false);
return result;
} finally {
try {
ftpClient.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
result.put("resultSts", resultSts);
return result;
}
}
우선 다운로드 기능만 필요했기 때문에 다른 기능은 고려하지 않았고 FTP 연결 및 다운로드 기능만 만들었다.
@Value ("#{ftp['ftp.hostname']}")
String hostname;
@Value ("#{ftp['ftp.port']}")
int port;
@Value ("#{ftp['ftp.username']}")
String username;
@Value ("#{ftp['ftp.password']}")
String password;
public String getHostname() {
return hostname;
}
public void setHostname(String hostname) {
this.hostname = hostname;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
우선 ftp.properties 를 추가하여 그 안에 고객사의 ftp 접근 정보를 저장해놓았다.
위 FtpClient.java 파일을 bean에 등록해 놓았기에 서버가 올라갈때 ftp.properties 에서 일치하는 값들을 불러와 전역변수로 저장되도록 해놓는다.
getter, setter 도 만들어 놓았다. 혹시 쓸일 있을까봐..
ftpClient.connect(this.hostname, this.port);
int reply = ftpClient.getReplyCode();
if(!FTPReply.isPositiveCompletion(reply)) {
System.err.println("연결실패");
resultSts = false;
}
download 메소드 초입에 commons-net 라이브러리의 FTPClient 를 객체로 초기화시켜주었다.
전역변수로 저장되어있는 ftp 서버의 url 혹은 ip 와 port 정보를 사용해 ftp 서버와 연결한다.
getReplyCode를 통해 정상적으로 연결되어있는지 확인하고 연결이 실패되었다면 결과상태를 false로 저장한다.
boolean loginSts = ftpClient.login(this.username, this.password);
if(!loginSts) {
System.err.println("로그인실패");
resultSts = false;
}
ftp 서버와 연결이 되면 전역변수로 저장되어있는 사용자 정보를 사용해 ftp 서버에 접속한다.
로그인이 정상적으로 되었다면 true, 실패되었다면 false로 반환된다.
// 폴더 생성
File folder = new File(localFilePath);
if(!folder.exists()) {
folder.mkdirs();
}
저장할 폴더가 존재하지 않으면 에러가 발생하기 때문에 파일을 저장할 폴더를 생성해주어야한다.
yyyy/mm/dd 형식으로 저장할것이기 때문에 localFilePath를 매개변수로 전달받는다.
전달 받은 매개변수에 해당하는 경로에 해당하는 폴더가 없다면 생성한다.
File localPath = new File(localFilePath+"\\"+fileName);
OutputStream outputStream = new FileOutputStream(localPath);
boolean downloadSts = ftpClient.retrieveFile(remoteFilePath, outputStream);
if(!downloadSts) {
System.err.println("다운로드실패");
resultSts = false;
}
FTPFile[] files = ftpClient.listFiles(remoteFilePath);
if (files.length > 0) {
long fileSize = files[0].getSize();
result.put("fileSize", fileSize);
System.out.println("파일 크기: " + fileSize + " bytes");
} else {
System.err.println("파일을 찾을 수 없습니다.");
resultSts = false;
}
File 클래스를 통해 만들어진 저장 경로에 파일명을 지정하여 저장해준다.
OutputStream 을 통해 File 객체를 stream 화 시켜주고
ftp 서버에서 가져올 파일의 위치를 나타내는 매개변수와 스트림화된 저장할 위치+파일명을 retrieveFile 메소드를 통해 파일을 다운로드한다.
성공하면 true, 실패하면 false 를 반환한다.
파일 크기도 저장해야하서 파일 크기도 가져와야한다.
listFiles 메소드에 가져올 파일의 위치를 매개변수로 파일 정보를 가져온다.
가져온 파일 정보에서 getSize로 크기를 가져오면 된다.
outputStream.close();
ftpClient.logout();
ftpClient.disconnect();
모든 과정이 끝나면 모든 연결을 종료해주어야한다.