scp przez java

81

Jaka jest najlepsza metoda wykonania transferu scp za pomocą języka programowania Java? Wygląda na to, że mogę to zrobić za pomocą JSSE, JSch lub bibliotek Java Bouncy Castle. Żadne z tych rozwiązań nie wydaje się mieć łatwej odpowiedzi.

Lloyd Meinholz
źródło
2
czy możesz opisać problemy, które masz z różnymi bibliotekami, dlaczego nie działają one dla Ciebie?
Tim Howland,

Odpowiedzi:

59

Skończyło się na tym, że korzystałem z Jsch - było to całkiem proste i wydawało się, że skalowałem się całkiem nieźle ( łapałem kilka tysięcy plików co kilka minut).

Tim Howland
źródło
1
jsch okazał się lepszą alternatywą, ale dokumentacja jest okropna. Wskazówka od Abaraxa, aby spojrzeć na zadanie mrówek scp, była bardzo pomocna. Naprawdę nie jest jasne, czy projekt jest nadal bardzo aktywny. Dzięki za wskazówkę.
Lloyd Meinholz,
30
@LloydMeinholz: Napisałem Javadocs dla tej biblioteki.
Paŭlo Ebermann
Paul - świetna robota! Wyglądają naprawdę pomocnie.
Tim Howland
4
Uważam, że ta strona jest bardzo pouczająca: jcraft.com/jsch/examples
Daniel Kaplan
23

wtyczka: sshj to jedyny rozsądny wybór! Aby rozpocząć, zobacz poniższe przykłady: pobieranie , przesyłanie .

shikhar
źródło
4
Poszedłem z sshj na Jsch, ponieważ miał znacznie prostszy interfejs.
Chris,
1
Skorzystaj z głównej strony github lub pobierz ZIP
CrazyPyro
Pomiędzy jsch i sshj wybrałem sshj ze względu na prostszy, wyższy poziom API. Porównaj przykład przesyłania z odpowiedzi z równoważnym przykładem dla jsch: jcraft.com/jsch/examples/ScpTo.java.html . Być może dlatego został nazwany „jedynym rozsądnym wyborem”.
Bogdan Calmac
1
Co za strata czasu. Przykłady nie pokazują użytych argumentów. Dokumentacja innej zdalnej nazwy użytkownika nie istnieje. Unikaj tej sugestii ludzi.
Kieveli
17

Spójrz tutaj

To jest kod źródłowy zadania SCP Antsa. Kod w metodzie „wykonaj” to miejsce, w którym znajdują się jej nakrętki i śruby. To powinno dać ci rzetelny obraz tego, co jest wymagane. Wydaje mi się, że używa JSch.

Alternatywnie możesz również wykonać to zadanie Ant bezpośrednio z kodu Java.

abarax
źródło
7

Opakowałem Jsch kilkoma narzędziami, aby uczynić go nieco bardziej przyjaznym i nazwałem go

Jscp

Dostępne tutaj: https://github.com/willwarren/jscp

Narzędzie SCP do tarowania folderu, spakowania go i scpowania gdzieś, a następnie rozpakowania.

Stosowanie:

// create secure context
SecureContext context = new SecureContext("userName", "localhost");

// set optional security configurations.
context.setTrustAllHosts(true);
context.setPrivateKeyFile(new File("private/key"));

// Console requires JDK 1.7
// System.out.println("enter password:");
// context.setPassword(System.console().readPassword());

Jscp.exec(context, 
           "src/dir",
           "destination/path",
           // regex ignore list 
           Arrays.asList("logs/log[0-9]*.txt",
           "backups") 
           );

Zawiera również przydatne klasy - Scp i Exec oraz TarAndGzip, które działają w podobny sposób.

Wola
źródło
5

Jest to rozwiązanie wysokopoziomowe , nie trzeba odkrywać na nowo. Szybko i brudno!

1) Najpierw przejdź do http://ant.apache.org/bindownload.cgi i pobierz najnowszy plik binarny Apache Ant. (obecnie apache-ant-1.9.4-bin.zip).

2) Wypakuj pobrany plik i znajdź JAR ant-jsch.jar („apache-ant-1.9.4 / lib / ant-jsch.jar”). Dodaj ten plik JAR do swojego projektu . Również ant-launcher.jar i ant.jar.

3) Idź do Jcraft jsch SouceForge Project i pobierz jar. Obecnie jsch-0.1.52.jar . Dodaj również ten plik JAR do swojego projektu .

Teraz możesz łatwo użyć w kodzie java Ant Classes Scp do kopiowania plików przez sieć lub SSHExec do poleceń na serwerach SSH.

4) Przykładowy kod Scp:

// This make scp copy of 
// one local file to remote dir

org.apache.tools.ant.taskdefs.optional.ssh.Scp scp = new Scp();
int portSSH = 22;
String srvrSSH = "ssh.your.domain";
String userSSH = "anyuser"; 
String pswdSSH = new String ( jPasswordField1.getPassword() );
String localFile = "C:\\localfile.txt";
String remoteDir = "/uploads/";

scp.setPort( portSSH );
scp.setLocalFile( localFile );
scp.setTodir( userSSH + ":" + pswdSSH + "@" + srvrSSH + ":" + remoteDir );
scp.setProject( new Project() );
scp.setTrust( true );
scp.execute();
Fernando Santos
źródło
Próbuję tego, ale otrzymałem błąd, jeśli jakieś rozwiązanie, a następnie skomentuj ---> com.jcraft.jsch.JSchException: Session.connect: java.security.NoSuchAlgorithmException: Algorithm DH niedostępny
Karan
1
Jeśli potrzebujesz szybkiego rozwiązania, działa to jak magia i jest prostsze niż bezpośrednie użycie JSch, dzięki.
Haim Raman
Czy można odczytać ze zdalnego serwera za pomocą org.apache.tools.ant.taskdefs.optional.ssh.Scp?
Minisha
3

Projekt openssh wymienia kilka alternatyw Javy, Trilead SSH dla Javy wydaje się pasować do tego, o co prosisz.

Kyle Burton
źródło
Trilead wydaje się znacznie bardziej dojrzały niż Jsch, ale brakowało mu wsparcia SFTP i SCP, o co mi chodziło. Obecnie sftp obsługuje tylko get and put (potrzebuję również ls i rm), a obsługa scp została wymieniona jako eksperymentalna.
Lloyd Meinholz,
2

Używam tego SFTP API, które ma SCP o nazwie Zehon, jest świetne, tak łatwe w użyciu z dużą ilością przykładowego kodu. Oto witryna http://www.zehon.com


źródło
2

Spojrzałem na wiele z tych rozwiązań i wielu z nich nie lubiłem. Głównie dlatego, że irytujący krok polegający na konieczności identyfikacji znanych hostów. To i JSCH jest na absurdalnie niskim poziomie w stosunku do polecenia scp.

Znalazłem bibliotekę, która tego nie wymaga, ale jest spakowana i używana jako narzędzie wiersza poleceń. https://code.google.com/p/scp-java-client/

Przejrzałem kod źródłowy i odkryłem, jak go używać bez wiersza poleceń. Oto przykład przesyłania:

    uk.co.marcoratto.scp.SCP scp = new uk.co.marcoratto.scp.SCP(new uk.co.marcoratto.scp.listeners.SCPListenerPrintStream());
    scp.setUsername("root");
    scp.setPassword("blah");
    scp.setTrust(true);
    scp.setFromUri(file.getAbsolutePath());
    scp.setToUri("root@host:/path/on/remote");
    scp.execute();

Największym minusem jest to, że nie ma go w repozytorium Maven (które mogłem znaleźć). Ale łatwość użycia jest dla mnie tego warta.

Daniel Kaplan
źródło
1

jsCH świetnie się dla mnie sprawdził. Poniżej znajduje się przykład metody, która połączy się z serwerem sftp i pobierze pliki do określonego katalogu. Zaleca się trzymanie się z daleka od wyłączania StrictHostKeyChecking. Chociaż konfiguracja jest nieco trudniejsza, ze względów bezpieczeństwa normą powinno być określenie znanych hostów.

jsch.setKnownHosts ("C: \ Users \ test \ known_hosts"); Zalecana

JSch.setConfig ("StrictHostKeyChecking", "nie"); - Niepolecane

import com.jcraft.jsch.*;
 public void downloadFtp(String userName, String password, String host, int port, String path) {


        Session session = null;
        Channel channel = null;
        try {
            JSch ssh = new JSch();
            JSch.setConfig("StrictHostKeyChecking", "no");
            session = ssh.getSession(userName, host, port);
            session.setPassword(password);
            session.connect();
            channel = session.openChannel("sftp");
            channel.connect();
            ChannelSftp sftp = (ChannelSftp) channel;
            sftp.get(path, "specify path to where you want the files to be output");
        } catch (JSchException e) {
            System.out.println(userName);
            e.printStackTrace();


        } catch (SftpException e) {
            System.out.println(userName);
            e.printStackTrace();
        } finally {
            if (channel != null) {
                channel.disconnect();
            }
            if (session != null) {
                session.disconnect();
            }
        }

    }
Eduardo Dennis
źródło
1

Tak jak niektórzy tutaj, napisałem otokę wokół biblioteki JSch.

Nazywa się way-secshell i jest hostowany na GitHub:

https://github.com/objectos/way-secshell

// scp myfile.txt localhost:/tmp
File file = new File("myfile.txt");
Scp res = WaySSH.scp()
  .file(file)
  .toHost("localhost")
  .at("/tmp")
  .send();

źródło
1

JSch to przyjemna biblioteka do pracy. Ma dość prostą odpowiedź na twoje pytanie.

JSch jsch=new JSch();
  Session session=jsch.getSession(user, host, 22);
  session.setPassword("password");


  Properties config = new Properties();
  config.put("StrictHostKeyChecking","no");
  session.setConfig(config);
  session.connect();

  boolean ptimestamp = true;

  // exec 'scp -t rfile' remotely
  String command="scp " + (ptimestamp ? "-p" :"") +" -t "+rfile;
  Channel channel=session.openChannel("exec");
  ((ChannelExec)channel).setCommand(command);

  // get I/O streams for remote scp
  OutputStream out=channel.getOutputStream();
  InputStream in=channel.getInputStream();

  channel.connect();

  if(checkAck(in)!=0){
    System.exit(0);
  }

  File _lfile = new File(lfile);

  if(ptimestamp){
    command="T "+(_lfile.lastModified()/1000)+" 0";
    // The access time should be sent here,
    // but it is not accessible with JavaAPI ;-<
    command+=(" "+(_lfile.lastModified()/1000)+" 0\n");
    out.write(command.getBytes()); out.flush();
    if(checkAck(in)!=0){
      System.exit(0);
    }
  }

Pełny kod można znaleźć pod adresem

http://faisalbhagat.blogspot.com/2013/09/java-uploading-file-remotely-via-scp.html

faisalbhagat
źródło
1

Oto przykład przesyłania pliku za pomocą JSch :

ScpUploader.java:

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

import java.io.ByteArrayInputStream;
import java.util.Properties;

public final class ScpUploader
{
    public static ScpUploader newInstance()
    {
        return new ScpUploader();
    }

    private volatile Session session;
    private volatile ChannelSftp channel;

    private ScpUploader(){}

    public synchronized void connect(String host, int port, String username, String password) throws JSchException
    {
        JSch jsch = new JSch();

        Properties config = new Properties();
        config.put("StrictHostKeyChecking", "no");

        session = jsch.getSession(username, host, port);
        session.setPassword(password);
        session.setConfig(config);
        session.setInputStream(System.in);
        session.connect();

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

    public synchronized void uploadFile(String directoryPath, String fileName, byte[] fileBytes, boolean overwrite) throws SftpException
    {
        if(session == null || channel == null)
        {
            System.err.println("No open session!");
            return;
        }

        // a workaround to check if the directory exists. Otherwise, create it
        channel.cd("/");
        String[] directories = directoryPath.split("/");
        for(String directory : directories)
        {
            if(directory.length() > 0)
            {
                try
                {
                    channel.cd(directory);
                }
                catch(SftpException e)
                {
                    // swallowed exception

                    System.out.println("The directory (" + directory + ") seems to be not exist. We will try to create it.");

                    try
                    {
                        channel.mkdir(directory);
                        channel.cd(directory);
                        System.out.println("The directory (" + directory + ") is created successfully!");
                    }
                    catch(SftpException e1)
                    {
                        System.err.println("The directory (" + directory + ") is failed to be created!");
                        e1.printStackTrace();
                        return;
                    }

                }
            }
        }

        channel.put(new ByteArrayInputStream(fileBytes), directoryPath + "/" + fileName, overwrite ? ChannelSftp.OVERWRITE : ChannelSftp.RESUME);
    }

    public synchronized void disconnect()
    {
        if(session == null || channel == null)
        {
            System.err.println("No open session!");
            return;
        }

        channel.exit();
        channel.disconnect();
        session.disconnect();

        channel = null;
        session = null;
    }
}

AppEntryPoint.java:

import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.SftpException;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public final class AppEntryPoint
{
    private static final String HOST = "192.168.1.1";
    private static final int PORT = 22;
    private static final String USERNAME = "root";
    private static final String PASSWORD = "root";

    public static void main(String[] args) throws IOException
    {
        ScpUploader scpUploader = ScpUploader.newInstance();

        try
        {
            scpUploader.connect(HOST, PORT, USERNAME, PASSWORD);
        }
        catch(JSchException e)
        {
            System.err.println("Failed to connect the server!");
            e.printStackTrace();
            return;
        }

        System.out.println("Successfully connected to the server!");

        byte[] fileBytes = Files.readAllBytes(Paths.get("C:/file.zip"));

        try
        {
            scpUploader.uploadFile("/test/files", "file.zip", fileBytes, true); // if overwrite == false, it won't throw exception if the file exists
            System.out.println("Successfully uploaded the file!");
        }
        catch(SftpException e)
        {
            System.err.println("Failed to upload the file!");
            e.printStackTrace();
        }

        scpUploader.disconnect();
    }
}
Eng. Fouad
źródło
1

-: Trochę poprawiając odpowiedź Fernando, jeśli używasz Mavena do zarządzania zależnościami: -

pom.xml :

<dependency>
  <groupId>org.apache.ant</groupId>
  <artifactId>ant-jsch</artifactId>
  <version>${ant-jsch.version}</version>
</dependency>

Dodaj tę zależność w swoim projekcie. Najnowszą wersję można znaleźć tutaj .

Kod Java :

public void scpUpload(String source, String destination) {
    Scp scp = new Scp();
    scp.setPort(port);
    scp.setLocalFile(source);
    scp.setTodir(username + ":" + password + "@" + host + ":" + destination);
    scp.setProject(new Project());
    scp.setTrust(true);
    scp.execute();
}
Saikat
źródło
0

Muszę rekurencyjnie kopiować folder, po wypróbowaniu różnych rozwiązań, ostatecznie kończy się na ProcessBuilder + oczekiwanie / spawn

scpFile("192.168.1.1", "root","password","/tmp/1","/tmp");

public void scpFile(String host, String username, String password, String src, String dest) throws Exception {

    String[] scpCmd = new String[]{"expect", "-c", String.format("spawn scp -r %s %s@%s:%s\n", src, username, host, dest)  +
            "expect \"?assword:\"\n" +
            String.format("send \"%s\\r\"\n", password) +
            "expect eof"};

    ProcessBuilder pb = new ProcessBuilder(scpCmd);
    System.out.println("Run shell command: " + Arrays.toString(scpCmd));
    Process process = pb.start();
    int errCode = process.waitFor();
    System.out.println("Echo command executed, any errors? " + (errCode == 0 ? "No" : "Yes"));
    System.out.println("Echo Output:\n" + output(process.getInputStream()));
    if(errCode != 0) throw new Exception();
}
Burt
źródło