[JAVA] 자바 SFTP 파일 업로드, 파일 다운로드 (jsch 라이브러리 사용방법)

[JAVA] 자바 SFTP 파일 업로드, 파일 다운로드 (jsch 라이브러리 사용방법)

자바 FTP 파일 업로드, 다운로드를 구현하기 위해서 ​FTPSClient 사용하려고 했는데(관련 라이브러리 파일은 commons-net-2.2.jar) FTPSClient 는 SFTP 접속을 할 수 없었다.

아래처럼 SSH-2.0-OpenSSH_7.4 오류가 발생하면 SFTP 이므로 접속이 안되는 경우다.

org.apache.commons.net.MalformedServerReplyException: Could not parse response code.

Server Reply: SSH-2.0-OpenSSH_7.4

    at org.apache.commons.net.ftp.FTP.__getReply(FTP.java:316)

    at org.apache.commons.net.ftp.FTP._connectAction_(FTP.java:365)

    at org.apache.commons.net.ftp.FTPClient._connectAction_(FTPClient.java:630)

    at org.apache.commons.net.SocketClient.connect(SocketClient.java:164)

    at org.apache.commons.net.SocketClient.connect(SocketClient.java:184)

SFTP 접속을 하기 위해서는 jsch 라이브러리를 사용하면 된다. 관련 라이브러리 파일은 jsch-0.1.49.jar 이고, 다음 주소에서 다운로드 받을 수 있다. https://mvnrepository.com/artifact/com.jcraft/jsch/0.1.49


우선 JSchWrapper 라는 클래스를 만들었다.

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Properties;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;

public class JSchWrapper {

    private Session jschSession = null;
    private Channel channel = null;
    private ChannelSftp channelSftp = null;

    /**
     * 파일 업로드
     *
     * @param fileName
     * @param dirPath
     * @throws Exception
     */

    public boolean uploadFile(String fileName, String dirPath) throws Exception {
        boolean isSuccess = false;

        FileInputStream fis = null;

        try {
            // 대상폴더 이동
            channelSftp.cd(dirPath);

            File file = new File(fileName);
            fis = new FileInputStream(file);

            // 파일 업로드
            channelSftp.put(fis, file.getName());
            isSuccess = true;

            System.out.println(“File uploaded : “ + file.getAbsolutePath() + ” => “ + dirPath + “/” + file.getName());

        } catch (Exception e) {
            throw e;

        } finally {
            close(fis);
        }

        return isSuccess;
    }

    /**
     * 파일 다운로드
     *
     * @param remoteFilePath
     * @param localDirPath
     * @param overwrite
     * @return
     * @throws Exception
     */

    public boolean downloadFile(String remoteFilePath, String localDirPath, boolean overwrite) throws Exception {
        if (remoteFilePath == null || remoteFilePath.length() == 0) {
            return false;
        }

        boolean isSuccess = false;

        byte[] buffer = new byte[1024];

        BufferedInputStream bis = null;
        FileOutputStream fos = null;
        BufferedOutputStream bos = null;

        try {
            if (remoteFilePath.indexOf(“\\”) > -1) {
                remoteFilePath = remoteFilePath.replace(“\\”“/”);
            }

            String remoteFileName = “”;

            // 대상폴더 이동
            int lastSlashIndex = remoteFilePath.lastIndexOf(“/”);
            if (lastSlashIndex > -1) {
                String cdDir = remoteFilePath.substring(0, lastSlashIndex);
                remoteFileName = remoteFilePath.substring(lastSlashIndex + 1);
                channelSftp.cd(cdDir);
            } else {
                remoteFileName = remoteFilePath;
                channelSftp.cd(“/”);
            }

            File destFile = new File(localDirPath + File.separator + remoteFileName);
            if (destFile.exists()) {
                if (overwrite) {
                    destFile.delete();
                } else {
                    System.out.println(“File Download canceled. File already exists : “ + destFile.getAbsolutePath());
                    return false;
                }
            }

            // 파일 다운로드
            bis = new BufferedInputStream(channelSftp.get(remoteFileName));
            fos = new FileOutputStream(destFile);
            bos = new BufferedOutputStream(fos);
            int readCount = 0;
            while ((readCount = bis.read(buffer)) > 0) {
                bos.write(buffer, 0, readCount);
            }

            isSuccess = true;
            System.out.println(“File downloaded : “ + remoteFilePath + ” => “ + destFile.getAbsolutePath());

        } catch (Exception e) {
            throw e;

        } finally {
            close(bos);
            close(fos);
            close(bis);
        }

        return isSuccess;
    }

    /**
     * 폴더 생성
     *
     * @param dirPath
     * @param dirName
     * @throws Exception
     */

    public boolean mkdir(String dirPath, String dirName) throws Exception {
        boolean isSuccess = false;

        String destDirPath = dirPath + “/” + dirName;

        boolean destDirExists = false;

        try {
            channelSftp.cd(destDirPath);
            destDirExists = true;

        } catch (Exception e) {
            destDirExists = false;
        }

        if (destDirExists) {
            System.out.println(“Folder Creation canceled. Folder already exists : “ + destDirPath);
            return false;
        }

        // 대상폴더 이동
        channelSftp.cd(dirPath);

        // 폴더 생성
        channelSftp.mkdir(dirName);
        isSuccess = true;

        System.out.println(“Folder created : “ + destDirPath);
        return isSuccess;
    }

    /**
     * SFTP 접속하기
     *
     * @return
     * @throws JSchException
     * @throws Exception
     */

    public void connectSFTP(String host, int port, String userName, String password) throws Exception {
        // JSch 객체를 생성
        JSch jsch = new JSch();

        // JSch 세션 객체를 생성 (사용자 이름, 접속할 호스트, 포트 전달)
        jschSession = jsch.getSession(userName, host, port);

        // 패스워드 설정
        jschSession.setPassword(password);

        // 기타설정 적용
        Properties config = new Properties();
        config.put(“StrictHostKeyChecking”“no”);
        jschSession.setConfig(config);

        // 접속
        jschSession.connect();

        // sftp 채널 열기
        channel = jschSession.openChannel(“sftp”);

        // sftp 채널 연결
        channelSftp = (ChannelSftp) channel;
        channelSftp.connect();
    }

    /**
     * SFTP 접속해제
     */

    public void disconnectSFTP() {
        try {
            if (channelSftp != null && channelSftp.isConnected()) {
                channelSftp.disconnect();
            }
        } catch (Exception e) {
        } finally {
            channelSftp = null;
        }

        try {
            if (channel != null && channel.isConnected()) {
                channel.disconnect();
            }
        } catch (Exception e) {
        } finally {
            channel = null;
        }

        try {
            if (jschSession != null && jschSession.isConnected()) {
                jschSession.disconnect();
            }
        } catch (Exception e) {
        } finally {
            jschSession = null;
        }
    }

    /**
     * FileInputStream 객체 닫기
     *
     * @param fis
     */

    private void close(FileInputStream fis) {
        try {
            if (fis != null) {
                fis.close();
            }
        } catch (Exception e) {
        } finally {
            fis = null;
        }
    }

    /**
     * BufferedInputStream 객체 닫기
     *
     * @param bis
     */

    private void close(BufferedInputStream bis) {
        try {
            if (bis != null) {
                bis.close();
            }
        } catch (Exception e) {
        } finally {
            bis = null;
        }
    }

    /**
     * FileOutputStream 객체 닫기
     *
     * @param fos
     */

    private void close(FileOutputStream fos) {

        try {
            if (fos != null) {
                fos.flush();
            }
        } catch (Exception e) {
        }

        try {
            if (fos != null) {
                fos.close();
            }
        } catch (Exception e) {
        } finally {
            fos = null;
        }
    }

    /**
     * BufferedOutputStream 객체 닫기
     *
     * @param bos
     */

    private void close(BufferedOutputStream bos) {

        try {
            if (bos != null) {
                bos.flush();
            }
        } catch (Exception e) {
        }

        try {
            if (bos != null) {
                bos.close();
            }
        } catch (Exception e) {
        } finally {
            bos = null;
        }
    }
}

위와 같이 JSchWrapper 라는 클래스를 만들어뒀기 때문에 실제 사용은 간편하다.

아래는 SFTP 접속, 폴더 생성, 파일 업로드, 파일 다운로드, SFTP 접속해제를 하는 자바코드다.


실행하기 전에 C:\ 드라이브에 test라는 폴더를 만들고, test 폴더 안에 download 폴더와 upload 폴더를 만든다.

(C:\test\download 폴더 생성, C:\test\upload 폴더 생성)


그리고 C:\test\upload 폴더 안에 임의의 그림파일을 만들고 파일명을 0001.png 이라고 정한다.

(C:\test\upload\0001.png 그림파일 준비)


이후 아래 코드를 실행했을 때 C:\test\download 폴더 안에 0001.png 파일이 다운로드 받아지면 성공이다.


public class TestClass {

    public static void main(String[] args) {
        JSchWrapper jschWrapper = null;

        try {
            jschWrapper = new JSchWrapper();

            // SFTP 접속하기 (주소, 포트번호, 사용자아이디, 패스워드)
            jschWrapper.connectSFTP(“itarchives.cafe24.com”, 22, “username”“1234”);

            // /itarchives 폴더 위치에 test 폴더 생성
            jschWrapper.mkdir(“/itarchives”“test”);

            // C:\\test\\upload\\0001.png 파일을 /itarchives/test 위치에 업로드
            jschWrapper.uploadFile(“C:\\test\\upload\\0001.png”“/itarchives/test”);

            // /itarchives/test/0001.png 파일을 C:\\test\\download 위치에 다운로드
            jschWrapper.downloadFile(“/itarchives/test/0001.png”“C:\\test\\download”, false);

        } catch (Exception e) {
            e.printStackTrace();

        } finally {
            // SFTP 접속해제
            jschWrapper.disconnectSFTP();
        }
    }
}


실행결과

Folder created : /itarchives/test

File uploaded : C:\test\upload\0001.png => /itarchives/test/0001.png

File downloaded : /itarchives/test/0001.png => C:\test\download\0001.png



참고사이트 : https://steemit.com/kr-dev/@capslock/java-sftp-using-jsch-sftp