scp 通过 java

Posted

技术标签:

【中文标题】scp 通过 java【英文标题】:scp via java 【发布时间】:2010-09-17 00:14:50 【问题描述】:

通过 Java 编程语言执行 scp 传输的最佳方法是什么?看来我可以通过 JSSE、JSch 或 bouncy castle java 库来执行此操作。这些解决方案似乎都没有一个简单的答案。

【问题讨论】:

您能分解一下您在使用各种库时遇到的问题吗,为什么它们不适合您? 【参考方案1】:

openssh project 列出了几个 Java 替代方案,Trilead SSH for Java 似乎符合您的要求。

【讨论】:

Trilead 似乎比 Jsch 成熟得多,但缺乏对 sftp 和 scp 的支持,这正是我所追求的。目前,sftp 只支持 get 和 put(我也需要 ls 和 rm),并且 scp 支持被列为体验。【参考方案2】:

看看 here

这是 Ants 的 SCP 任务的源代码。 “执行”方法中的代码是它的具体细节。这应该让您对所需的内容有一个公平的了解。我相信它使用 JSch。

或者,您也可以直接从您的 java 代码中执行此 Ant 任务。

【讨论】:

【参考方案3】:

我最终使用了Jsch——它非常简单,而且似乎可以很好地扩展(我每隔几分钟就会抓取几千个文件)。

【讨论】:

jsch 原来是更好的选择,但文档很糟糕。来自 Abarax 的关于查看 ants scp 任务的提示非常有帮助。目前还不清楚该项目是否仍然非常活跃。感谢您的提示。 @LloydMeinholz:我为这个库写了Javadocs。 保罗-干得好!他们看起来真的很有帮助。 我发现这个页面信息量很大:jcraft.com/jsch/examples【参考方案4】:

我使用这个 SFTP API,它有一个叫做 Zehon 的 SCP,它很棒,很容易使用,有很多示例代码。这里是网站http://www.zehon.com

【讨论】:

【参考方案5】:

plug:sshj 是唯一明智的选择!请参阅以下示例以开始使用:download、upload。

【讨论】:

我选择了 sshj 而不是 Jsch,因为它的界面要简单得多。 使用主github site或download the ZIP 在 jsch 和 sshj 之间,我选择了 sshj,因为它更简单、更高级别的 API。将答案中的上传示例与 jsch 的等效示例进行比较:jcraft.com/jsch/examples/ScpTo.java.html。这可能就是为什么它被称为“唯一明智的选择”。 真是浪费我的时间。示例不显示使用的参数。不存在不同的远程用户名文档。避免这个建议的人。【参考方案6】:

我用一些实用方法包装了 Jsch,让它更友好一些,并称之为

Jscp

可在此处获取:https://github.com/willwarren/jscp

SCP 实用程序 tar 一个文件夹,压缩它,然后将它 scp 到某个地方,然后解压缩。

用法:

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

还包括有用的类 - Scp 和 Exec,以及 TarAndGzip,它们的工作方式几乎相同。

【讨论】:

【参考方案7】:

我写了一个 scp 服务器,它比其他的要容易得多。我使用 Apache MINA 项目(Apache SSHD)来开发它。你可以看这里:https://github.com/boomz/JSCP 您也可以从/jar 目录下载jar 文件。 如何使用?看一看:https://github.com/boomz/JSCP/blob/master/src/Main.java

【讨论】:

【参考方案8】:

JSch 是一个不错的库。它为您的问题提供了相当简单的答案。

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

你可以在

找到完整的代码

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

【讨论】:

【参考方案9】:

我查看了很多这样的解决方案,但其中很多都不喜欢。主要是因为必须识别已知主机的烦人步骤。相对于 scp 命令,这和 JSCH 处于可笑的低水平。

我找到了一个不需要此功能的库,但它已捆绑并用作命令行工具。 https://code.google.com/p/scp-java-client/

我查看了源代码并发现了如何在没有命令行的情况下使用它。以下是上传示例:

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

最大的缺点是它不在 maven repo 中(我可以找到)。但是,易用性对我来说是值得的。

【讨论】:

【参考方案10】:

jsCH 对我来说非常有用。下面是连接到 sftp 服务器并将文件下载到指定目录的方法示例。建议不要禁用 StrictHostKeyChecking。虽然设置起来有点困难,但出于安全原因,指定已知主机应该是常态。

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

JSch.setConfig("StrictHostKeyChecking", "no"); - 不推荐

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

    

【讨论】:

【参考方案11】:

像这里的一些人一样,我最终为 JSch 库编写了一个包装器。

它被称为 way-secshell,它托管在 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();

【讨论】:

【参考方案12】:

这是高级解决方案,无需重新发明。又快又脏!

1) 首先,转到http://ant.apache.org/bindownload.cgi 并下载最新的Apache Ant 二进制文件。 (现在,apache-ant-1.9.4-bin.zip)。

2) 解压下载的文件,找到JAR ant-jsch.jar ("apache-ant-1.9.4/lib/ant-jsch.jar" )。 将此 JAR 添加到您的项目中。还有 ant-launcher.jar 和 ant.jar。

3) 转到Jcraft jsch SouceForge Project 并下载jar。如今,jsch-0.1.52.jar。另外将此 JAR 添加到您的项目中

现在,您是否可以轻松地将 Ant 类 Scp 用于通过网络复制文件或 SSHExec 用于 SSH 服务器中的命令的 java 代码。

4) 代码示例 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();

【讨论】:

我正在尝试这个,但如果有任何解决方案出现错误,请发表评论---> com.jcraft.jsch.JSchException: Session.connect: java.security.NoSuchAlgorithmException: 算法 DH 不可用 如果您需要一个快速的解决方案,这就像魔术一样,并且比直接使用 JSch 更简单,谢谢。 可以通过 org.apache.tools.ant.taskdefs.optional.ssh.Scp 从远程服务器读取?【参考方案13】:

我需要递归复制文件夹,在尝试了不同的解决方案后,最终以 ProcessBuilder + expect/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();

【讨论】:

【参考方案14】:

以下是使用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();
    

【讨论】:

【参考方案15】:

-:如果您使用 Maven 进行依赖管理,请稍微完善一下费尔南多的答案:-

pom.xml

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

在您的项目中添加此依赖项。最新版本可以在here找到。

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

【讨论】:

以上是关于scp 通过 java的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 SCP 保护 AWS 标记的资源?

用scp命令通过SSH互传文件

scp从硬盘驱动器通过服务器复制

scp 通过 ssh 隧道打开

sh scp文件 - 通过ssh复制文件

sh 使用SCP通过SSH复制文件