scp a través de java

81

¿Cuál es el mejor método para realizar una transferencia scp a través del lenguaje de programación Java? Parece que puedo realizar esto a través de JSSE, JSch o las bibliotecas java del castillo hinchable. Ninguna de estas soluciones parece tener una respuesta fácil.

Lloyd Meinholz
fuente
2
¿Puede desglosar los problemas que tiene con las diversas bibliotecas, por qué no funcionan para usted?
Tim Howland

Respuestas:

59

Terminé usando Jsch , era bastante sencillo y parecía escalar bastante bien (estaba tomando unos pocos miles de archivos cada pocos minutos).

Tim Howland
fuente
1
jsch resultó ser la mejor alternativa, pero la documentación es horrible. El consejo de Abarax para ver la tarea scp de hormigas fue muy útil. Realmente no está claro si el proyecto aún está muy activo. Gracias por el consejo.
Lloyd Meinholz
30
@LloydMeinholz: escribí Javadocs para esta biblioteca.
Paŭlo Ebermann
Paulo- ¡gran trabajo! Se ven realmente útiles.
Tim Howland
4
Encuentro que
Daniel Kaplan
23

enchufe: sshj es la única opción sensata. Vea estos ejemplos para comenzar: descargar , cargar .

shikhar
fuente
4
Fui con sshj sobre Jsch ya que tenía una interfaz mucho más simple.
Chris
1
Use el sitio principal de github o descargue el ZIP
CrazyPyro
Entre jsch y sshj elegí sshj debido a la API de nivel superior más simple. Compare el ejemplo de carga de la respuesta con el ejemplo equivalente de jsch: jcraft.com/jsch/examples/ScpTo.java.html . Quizás por eso se le llamó "la única opción sensata".
Bogdan Calmac
1
¡Qué desperdicio de mi tiempo. Los ejemplos no muestran los argumentos utilizados. No existe documentación de nombre de usuario remoto diferente. Evite esta sugerencia gente.
Kieveli
17

Echa un vistazo aquí

Ese es el código fuente de la tarea SCP de Ants. El código en el método "ejecutar" es donde están las tuercas y tornillos. Esto debería darle una idea clara de lo que se requiere. Utiliza JSch, creo.

Alternativamente, también puede ejecutar directamente esta tarea Ant desde su código java.

abarax
fuente
7

Envolví Jsch con algunos métodos de utilidad para hacerlo un poco más amigable y lo llamé

Jscp

Disponible aquí: https://github.com/willwarren/jscp

Utilidad SCP para tar una carpeta, comprimirla y scp en alguna parte, luego descomprimirla.

Uso:

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

También incluye clases útiles: Scp y Exec, y TarAndGzip, que funcionan prácticamente de la misma manera.

Será
fuente
5

Esta es una solución de alto nivel , no es necesario reinventar. ¡Rápido y sucio!

1) Primero, vaya a http://ant.apache.org/bindownload.cgi y descargue el último binario de Apache Ant. (hoy en día, apache-ant-1.9.4-bin.zip).

2) Extraiga el archivo descargado y busque el JAR ant-jsch.jar ("apache-ant-1.9.4 / lib / ant-jsch.jar"). Agregue este JAR en su proyecto . También ant-launcher.jar y ant.jar.

3) Vaya a Jcraft jsch SouceForge Project y descargue el archivo jar. Hoy en día, jsch-0.1.52.jar . También agregue este JAR en su proyecto .

Ahora, ¿puedes usar fácilmente en código java las clases Ant Scp para copiar archivos a través de la red o SSHExec para comandos en servidores SSH?

4) Ejemplo de código 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
fuente
Estoy intentando esto pero tengo un error si hay alguna solución, por favor comente ---> com.jcraft.jsch.JSchException: Session.connect: java.security.NoSuchAlgorithmException: Algorithm DH no disponible
Karan
1
Si necesita una solución rápida, esto funciona como magia y es más simple que usar JSch directamente, gracias.
Haim Raman
¿Es posible leer desde un servidor remoto con org.apache.tools.ant.taskdefs.optional.ssh.Scp?
Minisha
3

El proyecto openssh enumera varias alternativas de Java, Trilead SSH para Java parece encajar con lo que está pidiendo.

Kyle Burton
fuente
Trilead parece mucho más maduro que Jsch, pero carecía de soporte sftp y scp, que es lo que buscaba. Actualmente, sftp solo admite get y put (también necesito ls y rm) y el soporte scp se enumeró como experimental.
Lloyd Meinholz
2

Utilizo esta API SFTP que tiene SCP llamada Zehon, es genial, muy fácil de usar con una gran cantidad de código de muestra. Aquí está el sitio http://www.zehon.com


fuente
2

Miré muchas de estas soluciones y no me gustaron muchas de ellas. Principalmente debido al molesto paso de tener que identificar sus hosts conocidos. Eso y JSCH está en un nivel ridículamente bajo en relación con el comando scp.

Encontré una biblioteca que no requiere esto, pero está agrupada y se usa como una herramienta de línea de comandos. https://code.google.com/p/scp-java-client/

Revisé el código fuente y descubrí cómo usarlo sin la línea de comandos. Aquí hay un ejemplo de carga:

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

El mayor inconveniente es que no está en un repositorio de maven (que pude encontrar). Pero, para mí, la facilidad de uso lo vale.

Daniel Kaplan
fuente
1

jsCH ha funcionado muy bien para mí. A continuación se muestra un ejemplo de un método que se conectará al servidor sftp y descargará archivos al directorio especificado. Se recomienda evitar desactivar StrictHostKeyChecking. Aunque un poco más difícil de configurar, por razones de seguridad, especificar los hosts conocidos debería ser la norma.

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

JSch.setConfig ("StrictHostKeyChecking", "no"); - no recomendado

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
fuente
1

Como algunos aquí, terminé escribiendo un contenedor alrededor de la biblioteca JSch.

Se llama way-secshell y está alojado en 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();

fuente
1

JSch es una buena biblioteca para trabajar. Tiene una respuesta bastante fácil para su pregunta.

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

Puede encontrar el código completo en

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

faisalbhagat
fuente
1

Aquí hay un ejemplo para cargar un archivo usando 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();
    }
}
Ing.Fouad
fuente
0

Necesito copiar la carpeta de forma recursiva, después de probar diferentes soluciones, finalmente termino con ProcessBuilder + wait / 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
fuente
0

-: Refinando un poco la respuesta de Fernando, si usa Maven para la gestión de dependencias: -

pom.xml :

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

Agregue esta dependencia en su proyecto. La última versión se puede encontrar aquí .

Código 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
fuente