사실 별 재미있는 작업은 아니지만, 없으면 또 만들어야 하고 해서 잊어버릴까 한번 다시 만들어 봅니다.
https://blog.naver.com/tommybee/220111872151
FTP 클라이언트를 만들어 보기로 한다. 실제로 인터넷 상에 떠돌아 다니는 멜론 실시간 음악을 받아보자...
#아파치 #commons-net 을 사용해서 #FtpClient #래퍼 클래스를 만들어 보는 것이 오늘의 할 일입니다.
우선 고민이 되는 부분은 사용자 접속 정보를 외부 환경 설정에서 가져 오되, 이 접속 정보를 다시 외부에 오픈 할 것인가에 대한 부분입니다.
결론은 외부에 오픈하지 않는다는 것으로 가닥을 잡았습니다.
내부 연결 변수는 다 private 으로 정리하고, 생성자가 호출 될 때, FtpClient 클래스 인스턴스를 하나 만들어서 사용 합니다. 인스턴스가 하나 생성 될 때마다, 클라이언트를 하나씩 만들어 주겠죠.
private final String ip;
private final String port;
private final String user;
private final String passwd;
public FtpClientWrapper(final String ip, final String port, final String user, final String passwd)
{
this.ip = ip;
this.port = port;
this.user = user;
this.passwd = passwd;
LOG.setLevel(Level.INFO);
initFtpClient();
}
파일이 많지 않을 경우를 예상 했기 때문에 파일을 하나씩 원격에서 로컬로 옮겨 주는 메서드를 다음과 같이 만들어 주었습니다.
public boolean saveRemoteFileToCurrentDir(final String remoteFile, final String saveFile)
{
boolean isSuccess = false;
InputStream remoteFileStream = null;
OutputStream saveToLocationStream = null;
int flushCount = 100;
LOG.debug("saveRemoteFileToCurrentDir: {}/{}", ftpClient.isAvailable(), ftpClient.isConnected());
try {
saveToLocationStream = new BufferedOutputStream(new FileOutputStream(saveFile));
remoteFileStream = new BufferedInputStream(ftpClient.retrieveFileStream(remoteFile));
int returnCode = ftpClient.getReplyCode();
if (remoteFileStream == null || returnCode == 550) {
if(remoteFileStream!=null) remoteFileStream.close();
return false;
}
byte[] buffer = new byte[4096];
int byteRead = -1;
while((byteRead = remoteFileStream.read(buffer)) != -1)
{
saveToLocationStream.write(buffer, 0, byteRead);
//LOG.info("byteRead: {}", byteRead);
flushCount--;
if(flushCount == 0)
{
saveToLocationStream.flush();
flushCount = 100;
}
}
saveToLocationStream.flush();
saveToLocationStream.close();
remoteFileStream.close();
boolean success = ftpClient.completePendingCommand();
if (success) {
LOG.info("File has been downloaded successfully.{}", remoteFile);
}
isSuccess = true;
} catch (IOException e) {
e.printStackTrace();
LOG.info("IOException File: {}", remoteFile);
isSuccess = false;
}
finally
{
try {
if(saveToLocationStream!=null) saveToLocationStream.close();
if(remoteFileStream!=null) remoteFileStream.close();
} catch (IOException e) {
//e.printStackTrace();
}
}
return isSuccess;
}
아주 전통적인 방법인 Input/Ouput 스트림 방식으로 구현 했기 때문에 일반적인 JDK에서는 구동이 되지 않을까 합니다.
위의 메서드를 적용 할 경우, 옮겨놓을 디렉토리를 만들어 놓지 않은 경우
java.io.FileNotFoundException 오류가 날 것이 뻔합니다.따라서, 먼저 디렉토리를 만들어 놓고 옮겨야만 한다는 것입니다.
그리고 하나 더 유의 할 점은 #completePendingCommand 메서드를 호출 하기 전에 이미 파일 입출력 처리를 닫아야 한다는 것입니다.
saveToLocationStream.close();
remoteFileStream.close();
boolean success = ftpClient.completePendingCommand();
if (success) {
LOG.info("File has been downloaded successfully.{}", remoteFile);
}
그리고, completePendingCommand 메서드를 호출 하지 않으면 오작동을 할 수 있다고 API에 설명이 있습니다. 가급적이면 이 메서드를 호출 해서 #다운로드가 끝났는 지 여부를 확인 해 볼 필요는 있어 보입니다.
이 부분만 주의 한다면, 그냥 쓸만하지 않을까 합니다.
전체 소스
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketException;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
public class FtpClientWrapper {
private final static Logger LOG = (Logger) LoggerFactory.getLogger(FtpClientWrapper.class);
private FTPClient ftpClient;
private static final String FTP_ENC="EUC-KR";
private final String ip;
private final String port;
private final String user;
private final String passwd;
private static final int SOCK_TIME_OUT = 2 * 60 * 1000;
public FtpClientWrapper(final String ip, final String port, final String user, final String passwd)
{
this.ip = ip;
this.port = port;
this.user = user;
this.passwd = passwd;
LOG.setLevel(Level.INFO);
initFtpClient();
}
private void initFtpClient() {
ftpClient = new FTPClient();
ftpClient.setControlEncoding(FTP_ENC);
LOG.info("FTP server connection to.{}/{}", ip, port);
try {
ftpClient.connect(ip, Integer.parseInt(port));
} catch (NumberFormatException | IOException e) {
LOG.info("FTP server connection failed.{}/{}", ip, port);
e.printStackTrace();
}
int reply = ftpClient.getReplyCode(); // 응답코드가 비정상이면 종료합니다
if (!FTPReply.isPositiveCompletion(reply)) {
try {
ftpClient.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
LOG.info("FTP server refused connection.");
} else {
LOG.info("Success to connect : {} \n", ftpClient.getReplyString());
try {
ftpClient.setSoTimeout(SOCK_TIME_OUT);
} catch (SocketException e) {
LOG.error("Time out : {}", e);
} // 현재 커넥션 timeout을 millisecond 값으로 입력합니다
try {
ftpClient.login(user, passwd);
LOG.info("Success to login by following user : {}", user);
} catch (IOException e) {
LOG.info("Fail to login by following user : {}", user);
e.printStackTrace();
} // 로그인 유저명과 비밀번호를 입력 합니다
ftpClient.enterLocalPassiveMode();
try {
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public boolean saveRemoteFileToCurrentDir(final String remoteFile, final String saveFile)
{
boolean isSuccess = false;
InputStream remoteFileStream = null;
OutputStream saveToLocationStream = null;
int flushCount = 100;
LOG.debug("saveRemoteFileToCurrentDir: {}/{}", ftpClient.isAvailable(), ftpClient.isConnected());
try {
saveToLocationStream = new BufferedOutputStream(new FileOutputStream(saveFile));
remoteFileStream = new BufferedInputStream(ftpClient.retrieveFileStream(remoteFile));
int returnCode = ftpClient.getReplyCode();
if (remoteFileStream == null || returnCode == 550) {
if(remoteFileStream!=null) remoteFileStream.close();
return false;
}
byte[] buffer = new byte[4096];
int byteRead = -1;
while((byteRead = remoteFileStream.read(buffer)) != -1)
{
saveToLocationStream.write(buffer, 0, byteRead);
//LOG.info("byteRead: {}", byteRead);
flushCount--;
if(flushCount == 0)
{
saveToLocationStream.flush();
flushCount = 100;
}
}
saveToLocationStream.flush();
if(saveToLocationStream!=null) saveToLocationStream.close();
if(remoteFileStream!=null) remoteFileStream.close();
boolean success = ftpClient.completePendingCommand();
if (success) {
LOG.info("File has been downloaded successfully.{}", remoteFile);
}
isSuccess = true;
} catch (IOException e) {
e.printStackTrace();
LOG.info("IOException File: {}", remoteFile);
isSuccess = false;
}
finally
{
try {
if(saveToLocationStream!=null) saveToLocationStream.close();
if(remoteFileStream!=null) remoteFileStream.close();
} catch (IOException e) {
//e.printStackTrace();
}
}
return isSuccess;
}
public boolean releaseConnection()
{
boolean isSuccessToRelease = false;
try {
if(ftpClient.isConnected())
{
ftpClient.logout();
ftpClient.disconnect();
}
isSuccessToRelease = true;
} catch (IOException e) {
e.printStackTrace();
isSuccessToRelease = false;
}
return isSuccessToRelease;
}
}
이상.
'프로그래밍' 카테고리의 다른 글
[C] iconv API 사용하기 (0) | 2023.01.20 |
---|---|
[Java]apache commons 를 이용한 tar압축 풀기 (2) | 2023.01.19 |
[Java] JTable, JscrollPane을 사용한 스크롤 바 활성화 (0) | 2023.01.16 |
프로그래밍 씨,씨,씨 - 함수, union (0) | 2023.01.11 |
프로그래밍 씨,씨,씨 - 함수, union (0) | 2023.01.10 |