SFTP를 통해 서버에서 파일을 검색하는 방법은 무엇입니까?


답변:


198

또 다른 옵션은 JSch 라이브러리를 보는 것 입니다. JSch는 Eclipse, Ant 및 Apache Commons HttpClient를 포함하여 몇 가지 대규모 오픈 소스 프로젝트에 선호되는 라이브러리 인 것 같습니다.

사용자 / 패스 및 인증서 기반 로그인뿐만 아니라 다른 맛있는 SSH2 기능의 모든 호스트를 훌륭하게 지원합니다.

SFTP를 통한 간단한 원격 파일 검색은 다음과 같습니다. 오류 처리는 독자의 연습으로 남습니다. :-)

JSch jsch = new JSch();

String knownHostsFilename = "/home/username/.ssh/known_hosts";
jsch.setKnownHosts( knownHostsFilename );

Session session = jsch.getSession( "remote-username", "remote-host" );    
{
  // "interactive" version
  // can selectively update specified known_hosts file 
  // need to implement UserInfo interface
  // MyUserInfo is a swing implementation provided in 
  //  examples/Sftp.java in the JSch dist
  UserInfo ui = new MyUserInfo();
  session.setUserInfo(ui);

  // OR non-interactive version. Relies in host key being in known-hosts file
  session.setPassword( "remote-password" );
}

session.connect();

Channel channel = session.openChannel( "sftp" );
channel.connect();

ChannelSftp sftpChannel = (ChannelSftp) channel;

sftpChannel.get("remote-file", "local-file" );
// OR
InputStream in = sftpChannel.get( "remote-file" );
  // process inputstream as needed

sftpChannel.exit();
session.disconnect();

1
Cheekysoft, Jsch를 사용하는 동안 sftp-server에서 파일을 제거해도 작동하지 않는 것으로 나타났습니다. 또한 파일 이름 바꾸기도 작동하지 않습니다. 어떤 아이디어라도 제발 ??? Andy

1
죄송합니다. 현재로서는 작업하지 않습니다. (이러한 답변은 원래 질문에 대한 새로운 답변이
아니라이

1
세션 할당 후 해당 코드 블록은 무엇입니까? 내가 본 적이없는 멋진 Java 구문입니까? 그렇다면 어떻게 그렇게 기록 되었습니까?
Michael Peterson

3
@ p1x3l5 표준 자바 구문은 블록이 어디에나 삽입 될 수있게한다; 원하는 경우 변수 범위를보다 세밀하게 제어하는 ​​데 사용할 수 있습니다. 그러나이 경우 두 가지 구현 선택을 나타내는 데 도움이되는 시각적 도움 일뿐입니다. 즉, 사용자에게 암호를 요청하는 대화식 버전을 사용하거나 사용자 개입이 필요없는 하드 코딩 된 암호를 사용하지만 추가 보안 위험이있을 수 있습니다.
Cheekysoft

109

다음은 ssh 키 검사에 대해 걱정할 필요없이 JSch 를 사용하는 예제의 완전한 소스 코드입니다 .

import com.jcraft.jsch.*;

public class TestJSch {
    public static void main(String args[]) {
        JSch jsch = new JSch();
        Session session = null;
        try {
            session = jsch.getSession("username", "127.0.0.1", 22);
            session.setConfig("StrictHostKeyChecking", "no");
            session.setPassword("password");
            session.connect();

            Channel channel = session.openChannel("sftp");
            channel.connect();
            ChannelSftp sftpChannel = (ChannelSftp) channel;
            sftpChannel.get("remotefile.txt", "localfile.txt");
            sftpChannel.exit();
            session.disconnect();
        } catch (JSchException e) {
            e.printStackTrace();  
        } catch (SftpException e) {
            e.printStackTrace();
        }
    }
}

15
finally블록은 항상 실행되도록하기 위해, 채널 정리 코드를 포함하는 데 사용되어야한다.
hotshot309

나는 지금이 예외를 com.jcraft.jsch.JSchException: Session.connect: java.security.InvalidAlgorithmParameterException: Prime size must be multiple of 64, and can only range from 512 to 2048 (inclusive)
겪고

JSCH에 0 또는 1 개의 추가 종속성이 있음을 발견했습니다. 압축을 사용하지 않으면 JZLIB 종속성을 무시할 수 있습니다. // 압축 세션을 비활성화합니다. setConfig ( "compression.s2c", "none"); session.setConfig ( "compression.c2s", "없음");
englebart

1
엄격한 호스트 확인이 없으면 중간자 공격에 취약합니다.
rustyx

44

아래는 Apache Common VFS를 사용한 예입니다.

FileSystemOptions fsOptions = new FileSystemOptions();
SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(fsOptions, "no");
FileSystemManager fsManager = VFS.getManager();
String uri = "sftp://user:password@host:port/absolute-path";
FileObject fo = fsManager.resolveFile(uri, fsOptions);

5
또 다른 좋은 방법은 시간 제한을 설정하여 원격 시스템이 오프라인 상태 일 때 영원히 멈추지 않도록하는 것입니다. 호스트 키 확인 비활성화와 마찬가지로이 작업을 수행 할 수 있습니다. SftpFileSystemConfigBuilder.getInstance (). setTimeout (fsOptions, 5000);
Scott Jones

여러 SFTP 클라이언트를 동시에 사용할 때이 연결을 닫으려면 어떻게해야합니까?
2Big2BeSmall

2
비밀번호에 @ 기호가 있으면 어떻게합니까?
사용자 3

23

이것이 내가 http://sourceforge.net/projects/sshtools/ 와 함께 만든 해결책이었습니다 (명확성을 위해 대부분의 오류 처리는 생략되었습니다). 이것은 내 블로그 에서 발췌 한 것입니다

SshClient ssh = new SshClient();
ssh.connect(host, port);
//Authenticate
PasswordAuthenticationClient passwordAuthenticationClient = new PasswordAuthenticationClient();
passwordAuthenticationClient.setUsername(userName);
passwordAuthenticationClient.setPassword(password);
int result = ssh.authenticate(passwordAuthenticationClient);
if(result != AuthenticationProtocolState.COMPLETE){
     throw new SFTPException("Login to " + host + ":" + port + " " + userName + "/" + password + " failed");
}
//Open the SFTP channel
SftpClient client = ssh.openSftpClient();
//Send the file
client.put(filePath);
//disconnect
client.quit();
ssh.disconnect();

7
나는 (필요하게), 내가 요구 한 원본 사이트 / 다운로드에 대해서는 잘 작동했지만 새로운 사이트에 대해서는 작동하기를 거부했습니다. 나는 JSch로 전환하는 과정에있다
David Hayes

23

Jsch의 훌륭한 추상화는 Apache commons-vfs 이며 SFTP 파일을 거의 투명하게 액세스하고 쓰는 가상 파일 시스템 API를 제공합니다. 우리를 위해 잘 일했다.


1
사전 공유 키를 commons-vfs와 함께 사용할 수 있습니까?
Benedikt Waldvogel

2
네 그렇습니다. 비표준 ID가 필요한 경우 SftpFileSystemConfigBuilder.getInstance (). setIdentities (...)를 호출 할 수 있습니다.
Russ Hayward

사전 공유 키를 사용할 수 있습니다. 그러나이 키에는 암호가 없어야합니다. OtrosLogViewer는 VFS와 함께 SSH 키 인증을 사용하고 있지만 키에서 암호를 제거해야합니다 ( code.google.com/p/otroslogviewer/wiki/SftpAuthPubKey )
KrzyH

19

SFTP를위한 3 가지 성숙 Java 라이브러리 인 Commons VFS, SSHJ 및 JSch를 잘 비교했습니다.

요약하면 SSHJ는 가장 명확한 API를 가지고 있으며 Commons VFS에서 제공하는 다른 스토리지 지원이 필요하지 않은 경우 가장 좋습니다.

다음은 github 에서 편집 한 SSHJ 예제입니다 .

final SSHClient ssh = new SSHClient();
ssh.loadKnownHosts(); // or, to skip host verification: ssh.addHostKeyVerifier(new PromiscuousVerifier())
ssh.connect("localhost");
try {
    ssh.authPassword("user", "password"); // or ssh.authPublickey(System.getProperty("user.name"))
    final SFTPClient sftp = ssh.newSFTPClient();
    try {
        sftp.get("test_file", "/tmp/test.tmp");
    } finally {
        sftp.close();
    }
} finally {
    ssh.disconnect();
}

2
파일을 InputStream으로 가져 오는 방법이 있습니까?
Johan

2
2019 년 sshj는 여전히 잘 유지 관리되고 Alpakka (Akka) 프로젝트에서 사용됩니다
Maxence

13

Apache Commons SFTP 라이브러리

모든 예제에 대한 공통 Java 특성 파일

serverAddress = 111.222.333.444

userId = myUserId

password = my 비밀번호

remoteDirectory = 제품 /

localDirectory = import /

SFTP를 사용하여 원격 서버로 파일 업로드

import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;

import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemOptions;
import org.apache.commons.vfs2.Selectors;
import org.apache.commons.vfs2.impl.StandardFileSystemManager;
import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder;

public class SendMyFiles {

 static Properties props;

 public static void main(String[] args) {

  SendMyFiles sendMyFiles = new SendMyFiles();
  if (args.length < 1)
  {
   System.err.println("Usage: java " + sendMyFiles.getClass().getName()+
     " Properties_file File_To_FTP ");
   System.exit(1);
  }

  String propertiesFile = args[0].trim();
  String fileToFTP = args[1].trim();
  sendMyFiles.startFTP(propertiesFile, fileToFTP);

 }

 public boolean startFTP(String propertiesFilename, String fileToFTP){

  props = new Properties();
  StandardFileSystemManager manager = new StandardFileSystemManager();

  try {

   props.load(new FileInputStream("properties/" + propertiesFilename));
   String serverAddress = props.getProperty("serverAddress").trim();
   String userId = props.getProperty("userId").trim();
   String password = props.getProperty("password").trim();
   String remoteDirectory = props.getProperty("remoteDirectory").trim();
   String localDirectory = props.getProperty("localDirectory").trim();

   //check if the file exists
   String filepath = localDirectory +  fileToFTP;
   File file = new File(filepath);
   if (!file.exists())
    throw new RuntimeException("Error. Local file not found");

   //Initializes the file manager
   manager.init();

   //Setup our SFTP configuration
   FileSystemOptions opts = new FileSystemOptions();
   SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(
     opts, "no");
   SftpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(opts, true);
   SftpFileSystemConfigBuilder.getInstance().setTimeout(opts, 10000);

   //Create the SFTP URI using the host name, userid, password,  remote path and file name
   String sftpUri = "sftp://" + userId + ":" + password +  "@" + serverAddress + "/" + 
     remoteDirectory + fileToFTP;

   // Create local file object
   FileObject localFile = manager.resolveFile(file.getAbsolutePath());

   // Create remote file object
   FileObject remoteFile = manager.resolveFile(sftpUri, opts);

   // Copy local file to sftp server
   remoteFile.copyFrom(localFile, Selectors.SELECT_SELF);
   System.out.println("File upload successful");

  }
  catch (Exception ex) {
   ex.printStackTrace();
   return false;
  }
  finally {
   manager.close();
  }

  return true;
 }


}

SFTP를 사용하여 원격 서버에서 파일 다운로드

import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;

import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemOptions;
import org.apache.commons.vfs2.Selectors;
import org.apache.commons.vfs2.impl.StandardFileSystemManager;
import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder;

public class GetMyFiles {

 static Properties props;

 public static void main(String[] args) {

  GetMyFiles getMyFiles = new GetMyFiles();
  if (args.length < 1)
  {
   System.err.println("Usage: java " + getMyFiles.getClass().getName()+
   " Properties_filename File_To_Download ");
   System.exit(1);
  }

  String propertiesFilename = args[0].trim();
  String fileToDownload = args[1].trim();
  getMyFiles.startFTP(propertiesFilename, fileToDownload);

 }

 public boolean startFTP(String propertiesFilename, String fileToDownload){

  props = new Properties();
  StandardFileSystemManager manager = new StandardFileSystemManager();

  try {

   props.load(new FileInputStream("properties/" + propertiesFilename));
   String serverAddress = props.getProperty("serverAddress").trim();
   String userId = props.getProperty("userId").trim();
   String password = props.getProperty("password").trim();
   String remoteDirectory = props.getProperty("remoteDirectory").trim();
   String localDirectory = props.getProperty("localDirectory").trim();


   //Initializes the file manager
   manager.init();

   //Setup our SFTP configuration
   FileSystemOptions opts = new FileSystemOptions();
   SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(
     opts, "no");
   SftpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(opts, true);
   SftpFileSystemConfigBuilder.getInstance().setTimeout(opts, 10000);

   //Create the SFTP URI using the host name, userid, password,  remote path and file name
   String sftpUri = "sftp://" + userId + ":" + password +  "@" + serverAddress + "/" + 
     remoteDirectory + fileToDownload;

   // Create local file object
   String filepath = localDirectory +  fileToDownload;
   File file = new File(filepath);
   FileObject localFile = manager.resolveFile(file.getAbsolutePath());

   // Create remote file object
   FileObject remoteFile = manager.resolveFile(sftpUri, opts);

   // Copy local file to sftp server
   localFile.copyFrom(remoteFile, Selectors.SELECT_SELF);
   System.out.println("File download successful");

  }
  catch (Exception ex) {
   ex.printStackTrace();
   return false;
  }
  finally {
   manager.close();
  }

  return true;
 }

}

SFTP를 사용하여 원격 서버에서 파일 삭제

import java.io.FileInputStream;
import java.util.Properties;

import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemOptions;
import org.apache.commons.vfs2.impl.StandardFileSystemManager;
import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder;

public class DeleteRemoteFile {

 static Properties props;

 public static void main(String[] args) {

  DeleteRemoteFile getMyFiles = new DeleteRemoteFile();
  if (args.length < 1)
  {
   System.err.println("Usage: java " + getMyFiles.getClass().getName()+
   " Properties_filename File_To_Delete ");
   System.exit(1);
  }

  String propertiesFilename = args[0].trim();
  String fileToDownload = args[1].trim();
  getMyFiles.startFTP(propertiesFilename, fileToDownload);

 }

 public boolean startFTP(String propertiesFilename, String fileToDownload){

  props = new Properties();
  StandardFileSystemManager manager = new StandardFileSystemManager();

  try {

   props.load(new FileInputStream("properties/" + propertiesFilename));
   String serverAddress = props.getProperty("serverAddress").trim();
   String userId = props.getProperty("userId").trim();
   String password = props.getProperty("password").trim();
   String remoteDirectory = props.getProperty("remoteDirectory").trim();


   //Initializes the file manager
   manager.init();

   //Setup our SFTP configuration
   FileSystemOptions opts = new FileSystemOptions();
   SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(
     opts, "no");
   SftpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(opts, true);
   SftpFileSystemConfigBuilder.getInstance().setTimeout(opts, 10000);

   //Create the SFTP URI using the host name, userid, password,  remote path and file name
   String sftpUri = "sftp://" + userId + ":" + password +  "@" + serverAddress + "/" + 
     remoteDirectory + fileToDownload;

   //Create remote file object
   FileObject remoteFile = manager.resolveFile(sftpUri, opts);

   //Check if the file exists
   if(remoteFile.exists()){
    remoteFile.delete();
    System.out.println("File delete successful");
   }

  }
  catch (Exception ex) {
   ex.printStackTrace();
   return false;
  }
  finally {
   manager.close();
  }

  return true;
 }

}


ssh-key (공개 키)를 사용하여 서버에서 파일을 복사하는 동안 구성하는 방법 내 서버와 원격 서버 사이에 ssh_trust를 만들어야하기 때문입니다.
MS Parmar

7

hierynomus / sshj 는 SFTP 버전 3을 완전히 구현했습니다 (OpenSSH가 구현하는 것).

SFTPUpload.java의 예제 코드

package net.schmizz.sshj.examples;

import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.sftp.SFTPClient;
import net.schmizz.sshj.xfer.FileSystemFile;

import java.io.File;
import java.io.IOException;

/** This example demonstrates uploading of a file over SFTP to the SSH server. */
public class SFTPUpload {

    public static void main(String[] args)
            throws IOException {
        final SSHClient ssh = new SSHClient();
        ssh.loadKnownHosts();
        ssh.connect("localhost");
        try {
            ssh.authPublickey(System.getProperty("user.name"));
            final String src = System.getProperty("user.home") + File.separator + "test_file";
            final SFTPClient sftp = ssh.newSFTPClient();
            try {
                sftp.put(new FileSystemFile(src), "/tmp");
            } finally {
                sftp.close();
            }
        } finally {
            ssh.disconnect();
        }
    }

}

2
좋은 작업!! 메인 페이지의 예제가 도움이 될 수 있습니다.
OhadR

4

JSch 라이브러리는 SFTP 서버에서 파일을 읽는 데 사용할 수있는 강력한 라이브러리입니다. 아래는 SFTP 위치에서 파일을 한 줄씩 읽는 테스트 된 코드입니다.

JSch jsch = new JSch();
        Session session = null;
        try {
            session = jsch.getSession("user", "127.0.0.1", 22);
            session.setConfig("StrictHostKeyChecking", "no");
            session.setPassword("password");
            session.connect();

            Channel channel = session.openChannel("sftp");
            channel.connect();
            ChannelSftp sftpChannel = (ChannelSftp) channel;

            InputStream stream = sftpChannel.get("/usr/home/testfile.txt");
            try {
                BufferedReader br = new BufferedReader(new InputStreamReader(stream));
                String line;
                while ((line = br.readLine()) != null) {
                    System.out.println(line);
                }

            } catch (IOException io) {
                System.out.println("Exception occurred during reading file from SFTP server due to " + io.getMessage());
                io.getMessage();

            } catch (Exception e) {
                System.out.println("Exception occurred during reading file from SFTP server due to " + e.getMessage());
                e.getMessage();

            }

            sftpChannel.exit();
            session.disconnect();
        } catch (JSchException e) {
            e.printStackTrace();
        } catch (SftpException e) {
            e.printStackTrace();
        }

전체 프로그램 은 블로그 를 참조하십시오 .


3

앤디, 원격 시스템에서 파일을 삭제하려면 (channelExec)JSch 를 사용 하고 unix / linux 명령을 전달하여 삭제해야합니다.


2

연결 풀과 비동기 작업을 지원하는 강력하고 성숙한 SFTP 클라이언트 라이브러리 인 edtFTPj / PRO를 사용해보십시오 . FTP 및 FTPS도 지원하므로 안전한 파일 전송을위한 모든 기반이 포함됩니다.



2

위의 답변은 매우 도움이되었지만 "브로큰 채널", "rsa 키 알 수 없음"및 "패킷 손상"과 같은 다양한 예외에 직면하여 하루 동안 답변을 제공했습니다.

아래는 JSch 라이브러리를 사용하는 SFTP 파일 업로드 / 다운로드에 재사용 가능한 클래스입니다.

업로드 사용법 :

SFTPFileCopy upload = new SFTPFileCopy(true, /path/to/sourcefile.png", /path/to/destinationfile.png");

사용법 다운로드 :

SFTPFileCopy download = new SFTPFileCopy(false, "/path/to/sourcefile.png", "/path/to/destinationfile.png");

수업 코드 :

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UIKeyboardInteractive;
import com.jcraft.jsch.UserInfo;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.swing.JOptionPane;
import menue.Menue;

public class SFTPFileCopy1 {

    public SFTPFileCopy1(boolean upload, String sourcePath, String destPath) throws FileNotFoundException, IOException {
        Session session = null;
        Channel channel = null;
        ChannelSftp sftpChannel = null;
        try {
            JSch jsch = new JSch();
            //jsch.setKnownHosts("/home/user/.putty/sshhostkeys");
            session = jsch.getSession("login", "mysite.com", 22);
            session.setPassword("password");

            UserInfo ui = new MyUserInfo() {
                public void showMessage(String message) {

                    JOptionPane.showMessageDialog(null, message);

                }

                public boolean promptYesNo(String message) {

                    Object[] options = {"yes", "no"};

                    int foo = JOptionPane.showOptionDialog(null,
                            message,
                            "Warning",
                            JOptionPane.DEFAULT_OPTION,
                            JOptionPane.WARNING_MESSAGE,
                            null, options, options[0]);

                    return foo == 0;

                }
            };
            session.setUserInfo(ui);

            session.setConfig("StrictHostKeyChecking", "no");
            session.connect();
            channel = session.openChannel("sftp");
            channel.setInputStream(System.in);
            channel.setOutputStream(System.out);
            channel.connect();
            sftpChannel = (ChannelSftp) channel;

            if (upload) { // File upload.
                byte[] bufr = new byte[(int) new File(sourcePath).length()];
                FileInputStream fis = new FileInputStream(new File(sourcePath));
                fis.read(bufr);
                ByteArrayInputStream fileStream = new ByteArrayInputStream(bufr);
                sftpChannel.put(fileStream, destPath);
                fileStream.close();
            } else { // File download.
                byte[] buffer = new byte[1024];
                BufferedInputStream bis = new BufferedInputStream(sftpChannel.get(sourcePath));
                OutputStream os = new FileOutputStream(new File(destPath));
                BufferedOutputStream bos = new BufferedOutputStream(os);
                int readCount;
                while ((readCount = bis.read(buffer)) > 0) {
                    bos.write(buffer, 0, readCount);
                }
                bis.close();
                bos.close();
            }
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            if (sftpChannel != null) {
                sftpChannel.exit();
            }
            if (channel != null) {
                channel.disconnect();
            }
            if (session != null) {
                session.disconnect();
            }
        }
    }

    public static abstract class MyUserInfo
            implements UserInfo, UIKeyboardInteractive {

        public String getPassword() {
            return null;
        }

        public boolean promptYesNo(String str) {
            return false;
        }

        public String getPassphrase() {
            return null;
        }

        public boolean promptPassphrase(String message) {
            return false;
        }

        public boolean promptPassword(String message) {
            return false;
        }

        public void showMessage(String message) {
        }

        public String[] promptKeyboardInteractive(String destination,
                String name,
                String instruction,
                String[] prompt,
                boolean[] echo) {

            return null;
        }
    }
}


1

Zehon이라는 SFTP API를 사용합니다. 훌륭하고 많은 샘플 코드와 함께 사용하기 쉽습니다. 여기 사이트 http://www.zehon.com입니다


2
제혼은 죽은 것 같습니다. 그리고 소스는 어디에 있습니까? '무료'뒤에있는 '라이센스'는 무엇입니까?
rü-

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.