Jak odzyskać plik z serwera przez SFTP?

228

Próbuję pobrać plik z serwera za pomocą SFTP (w przeciwieństwie do FTPS) za pomocą Java. W jaki sposób mogę to zrobić?

David Hayes
źródło

Odpowiedzi:

198

Inną opcją jest rozważenie spojrzenia na bibliotekę JSch . JSch wydaje się być preferowaną biblioteką dla kilku dużych projektów open source, w tym między innymi Eclipse, Ant i Apache Commons HttpClient.

Ładnie obsługuje logowanie użytkownika / przepustkę i logowanie oparte na certyfikatach, a także całą gamę innych pysznych funkcji SSH2.

Oto proste zdalne pobieranie plików przez SFTP. Obsługa błędów pozostaje zadaniem dla czytelnika :-)

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();
Cheekysoft
źródło
1
Cheekysoft, zauważyłem - podczas korzystania z Jsch - usuwanie plików z serwera sftp nie działa. Również zmiana nazw plików nie działa. Wszelkie pomysły proszę ??? Andy
1
Niestety, nie jest to obecnie coś, z czym pracuję. (Proszę zostawić tego rodzaju odpowiedzi jako komentarze - jak ta wiadomość - a nie jako nową odpowiedź na pierwotne pytanie)
Cheekysoft 31.01.11
1
Co to za blok kodu po przypisaniu sesji? Czy to jakaś wymyślna składnia Java, której nigdy nie widziałem? Jeśli tak, to co osiąga bycie tak napisanym?
Michael Peterson
3
@ p1x3l5 standardowa składnia Java umożliwia wstawienie bloku w dowolnym miejscu; można go użyć, aby zapewnić lepszą kontrolę nad zmiennym zakresem, jeśli chcesz. Jednak w tym przypadku jest to tylko pomoc wizualna, która pomaga wskazać dwie opcje implementacji: albo użyj wersji interaktywnej, która żąda hasła od użytkownika, albo użyj hasła zakodowanego na stałe, które nie wymaga interwencji użytkownika, ale prawdopodobnie dodatkowe ryzyko bezpieczeństwa.
Cheekysoft,
109

Oto pełny kod źródłowy przykładu używającego JSch bez martwienia się o sprawdzenie klucza ssh.

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();
        }
    }
}
Iraklis
źródło
15
finallyBlok powinien być używany do włączenia oczyszczenia kodu kanału, aby zapewnić, że zawsze działa.
hotshot309,
Dostaję teraz ten wyjątek: 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)
anon58192932
Odkryłem, że JSCH ma 0 lub 1 dodatkowe zależności. Zignoruj ​​zależność JZLIB, jeśli wyłączysz kompresję. // wyłącz kompresję session.setConfig („kompresja.s2c”, „brak”); session.setConfig („ression.c2s ”,„ none ”);
englebart
1
Bez ścisłego sprawdzania hosta jesteś podatny na atak man-in-the-middle.
rustyx
44

Poniżej znajduje się przykład korzystania z 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);
Chris J
źródło
5
Kolejną miłą rzeczą jest ustawienie limitu czasu, tak aby zdalny system nie był zawieszony na zawsze. Możesz to zrobić tak samo, jak w przypadku wyłączania sprawdzania klucza hosta: SftpFileSystemConfigBuilder.getInstance (). SetTimeout (fsOptions, 5000);
Scott Jones
Jak radziłbyś zamknąć to połączenie, jeśli korzystasz z wielu klientów SFTP jednocześnie?
2Big2BeSmall
2
Co jeśli moje hasło zawiera symbol @?
Użytkownik3
23

To było rozwiązanie, które wymyśliłem http://sourceforge.net/projects/sshtools/ (większość błędów została pominięta dla jasności). To jest fragment mojego bloga

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();
David Hayes
źródło
7
Zgadzam się (z opóźnieniem), że działało dobrze dla oryginalnej strony / wymagałem pobrania, ale odmówiło pracy dla nowej. Jestem w trakcie zmiany na JSch
David Hayes
23

Ładną abstrakcją na Jsch jest Apache commons-vfs, który oferuje wirtualny interfejs API systemu plików, który sprawia, że ​​dostęp i zapis plików SFTP jest prawie przezroczysty. Pracował dla nas dobrze.

Boris Terzic
źródło
1
czy można używać wstępnie współdzielonych kluczy w połączeniu z commons-vfs?
Benedikt Waldvogel
2
Tak to jest. Jeśli potrzebujesz niestandardowych tożsamości, możesz wywołać SftpFileSystemConfigBuilder.getInstance (). SetIdentities (...).
Russ Hayward
Możesz użyć wstępnie udostępnionych kluczy. Ale te klucze muszą być bez hasła. OtrosLogViewer używa autoryzacji klucza SSH z VFS, ale wymaga usunięcia hasła z klucza ( code.google.com/p/otroslogviewer/wiki/SftpAuthPubKey )
KrzyH
19

Jest ładne porównanie 3 dojrzałych bibliotek Java dla SFTP: Commons VFS, SSHJ i JSch

Podsumowując, SSHJ ma najczystszy interfejs API i jest najlepszy z nich, jeśli nie potrzebujesz obsługi innych magazynów udostępnianych przez Commons VFS.

Oto edytowany przykład SSHJ z github :

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();
}
Sasha
źródło
2
Czy istnieje sposób na uzyskanie pliku jako InputStream?
Johan
2
sshj w 2019 roku jest nadal dobrze utrzymany i jest używany w projekcie Alpakka (Akka)
Maxence
13

Biblioteka SFTP Apache Commons

Wspólny plik właściwości Java dla wszystkich przykładów

serverAddress = 111.222.333.444

userId = myUserId

hasło = mojeHasło

remoteDirectory = produkty /

localDirectory = import /

Prześlij plik na zdalny serwer za pomocą 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;
 }


}

Pobierz plik ze zdalnego serwera za pomocą 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;
 }

}

Usuń plik na zdalnym serwerze za pomocą 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;
 }

}
AZ_
źródło
jak skonfigurować, mając ssh-key (klucz publiczny) do kopiowania plików na serwerze. Ponieważ muszę zrobić ssh_trust między moim serwerem a serwerem zdalnym.
MS Parmar
7

hierynomus / sshj ma pełną implementację SFTP w wersji 3 (co implementuje OpenSSH)

Przykładowy kod z 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();
        }
    }

}
Shikhar
źródło
2
dobra robota!! przykład na stronie głównej może być jednak pomocny.
OhadR
4

Biblioteka JSch to potężna biblioteka, której można użyć do odczytu pliku z serwera SFTP. Poniżej znajduje się testowany kod do odczytu pliku z lokalizacji SFTP linia po linii

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();
        }

Zapoznaj się z blogiem dla całego programu.

Ankur jain
źródło
3

Andy, aby usunąć plik na zdalnym systemie, musisz użyć (channelExec)JSch i przekazać polecenia unix / linux, aby go usunąć.

Pushpinder Rattan
źródło
2

Wypróbuj edtFTPj / PRO , dojrzałą, niezawodną bibliotekę klientów SFTP, która obsługuje pule połączeń i operacje asynchroniczne. Obsługuje również FTP i FTPS, więc wszystkie podstawy bezpiecznego transferu plików są objęte gwarancją.

Bruce Blackshaw
źródło
2

Chociaż powyższe odpowiedzi były bardzo pomocne, spędziłem jeden dzień, aby je uruchomić, z różnymi wyjątkami, takimi jak „uszkodzony kanał”, „nieznany klucz rsa” i „uszkodzony pakiet”.

Poniżej znajduje się działająca klasa wielokrotnego użytku dla PLIKÓW SFTP UPLOAD / DOWNLOAD przy użyciu biblioteki JSch.

Wykorzystanie przesyłania:

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

Pobierz użycie:

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

Kod klasy:

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;
        }
    }
}
Strefa
źródło
1

Używam tego SFTP API o nazwie Zehon, jest świetny, tak łatwy w użyciu z dużą ilością przykładowego kodu. Oto strona http://www.zehon.com


źródło
2
Zehon wydaje się martwy. A gdzie jest źródło? Jaka „licencja” kryje się za „bezpłatną”?
rü-
0

Najlepszym rozwiązaniem, jakie znalazłem, jest Paramiko . Jest wersja Java.

Brian Clapper
źródło
github.com/terencehonles/jaramiko jest porzucony na rzecz JSch (patrz zawiadomienie na github).
rü-