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ć?

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

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

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

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

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.


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

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

}


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

}

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.


3

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


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ą.



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


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


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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.