【问题标题】:How do I transfer a file from one directory to another using Java SFTP Library JSch?如何使用 Java SFTP Library JSch 将文件从一个目录传输到另一个目录?
【发布时间】:2015-09-25 17:17:33
【问题描述】:

我需要使用 JSch 库对文件传输进行编程。我有一个包含两个文件夹的简单目录 -

SFTP_1 文件夹中,我有一个位图图像。 SFTP_2 文件夹只是一个空文件夹。我的目标是使用 SFTP 将图像从 SFTP_1 传输到 SFTP_2 。

到目前为止,这是我的代码:

FileTransfer fileTransfer = new FileTransfer();              
      
JSch jsch = new JSch();

String host = "127.0.0.1";
int port = 22;

String user = "user";
Session session = jsch.getSession(user, host, port);      
session = jsch.getSession("username", "127.0.0.1", 22);
session.connect();

ChannelSftp sftp = null;
sftp = (ChannelSftp)session.openChannel("sftp") ; //channel;

sftp.rename(
    "C:\\Users\\ADMIN\\Desktop\\Work\\ConnectOne_Bancorp\\Java_Work\\SFTP_1\\house.bmp",
    "C:\\Users\\ADMIN\\Desktop\\Work\\ConnectOne_Bancorp\\Java_Work\\SFTP_2\\house.bmp");
session.disconnect();

我想做的只是将文件从我机器中的一个目录传输到另一个目录。任何提示表示赞赏,谢谢!

【问题讨论】:

    标签: java sftp jsch


    【解决方案1】:

    请注意,要在两个文件夹之间进行复制,不需要使用 SFTP。可以从一个文件夹复制到另一个文件夹,而无需涉及 SFTP 协议,该协议主要用于远程复制文件,从本地机器到远程机器,或从远程机器到(相同或不同)远程机器,或从远程机器到本地机器。

    这是因为 FTP 是基于网络的协议。所以使用它(或它的任何相关协议)将使用网络(或模拟网络)。

    JSch 提供的安全性旨在防止网络上发生的某些类型的攻击。它不会在机器内提供任何额外的安全性。

    要在单台机器上的文件夹之间复制文件,最简单的方法就是不要使用JSch,像这样

    private static void copyFileUsingJava7Files(File source, File dest)
            throws IOException {
        Files.copy(source.toPath(), dest.toPath());
    }
    

    还有其他技术,如果你真的想使用JSch,你需要意识到JSch必须提供很多“额外”的信息才能连接到你所在的机器,因为它会尝试连接到这个机器就好像它是通过网络连接的一样

    Session sessionRead = jsch.getSession("username", "127.0.0.1", 22);
    sessionRead.connect();
    
    Session sessionWrite = jsch.getSession("username", "127.0.0.1", 22);
    sessionWrite.connect();
    
    ChannelSftp channelRead = (ChannelSftp)sessionRead.openChannel("sftp");
    channelRead.connect();
    
    ChannelSftp channelWrite = (ChannelSftp)sessionWrite.openChannel("sftp");
    channelWrite.connect();
    
    PipedInputStream pin = new PipedInputStream(2048);
    PipedOutputStream pout = new PipedOutputStream(pin);
    
    channelRead.get("/path/to/your/file/including/filename.txt", pout);
    channelWrite.put(pin, "/path/to/your/file/destination/including/filename.txt");
    
    channelRead.disconnect();
    channelWrite.disconnect();
    
    sessionRead.disconnect();
    sessionWrite.disconnect();
    

    上面的代码缺少错误检查、异常处理以及如果文件丢失、网络不正常等情况的回退例程。但是你应该明白主要的想法。

    还应该很明显,使用不需要存在网络协议的网络协议会打开更多故障场景的大门。如果您的程序很快要复制不在您机器上的文件,请仅使用 SFTP 方法。

    【讨论】:

    • 虽然这确实可行,但我认为您不需要两个 SSH 会话。它应该通过单个 SSH 连接仅使用两个 SFTP 通道。通常,即使是单个 SFTP 通道也应该足够了。 SFTP 协议可以并行处理多个文件(读取一个,写入另一个)。但我不确定,如果 JSch SFTP 实现是为支持并行文件而构建的。
    • @MartinPrikryl 您可能是正确的,一个会话可能可用。我使用了两个,主要是因为在未来,我希望会话能够从同一个帐户和机器上迁移出去。我知道提出的问题是保证不会发生将它们从同一个帐户和计算机迁移出去的问题,但是由于他正在寻求网络协议,因此很可能有人计划移动这些东西,而且他没有被告知全貌(就像我们只有一台机器可以开发它,但稍后我们将拥有三台)。
    • 这可能也值得解释一下,为什么实际上需要下载并重新上传文件来复制它,而不是在服务器上就地复制它。还有其他选项,例如使用 cp shell 命令(如果有 shell 访问权限)。见Using SFTP in Java, How do I transfer a file from one folder to another?
    • @MartinPrikryl 我不确定会在哪里提出这样的问题。毕竟,这不是“如何做”答案的一部分;而且,答案可能很简单,例如“我不知道为什么,但有人告诉我,这样做是不可协商的要求”。再次,可能有一个合理的废话原因,就像你一样,我看不到这样的原因。无论哪种方式,我都不想让他回答“为什么?”的问题。因为这似乎只不过是一个被告知“你没有得到答案,因为你需要做其他事情!”的邀请。 :)
    【解决方案2】:

    其实JSch是为远程工作而设计的,文件系统修改就是此类工作之一。 @Edwin Buck 回答使用网络在远程主机上的本地文件夹之间进行处理。有更好的方法:

    session.connect();
    ChannelExec exec = (ChannelExec) session.openChannel("exec");
    exec.setCommand("cp a.out b.out");
    exec.connect();
    

    我手头没有窗户,因此我的示例是针对 unix 的。但是思路很简单:在远程主机上执行复制命令。

    【讨论】:

    • 问题是关于 SFTP 的。这不是 SFTP 解决方案。它依赖于 shell 访问。它依赖于平台。它仅适用于 *nix 服务器。
    • SFTP 是通过 SSH 传输文件。可以配置 SSH 服务和禁止执行,但在现实生活中并不常见。这个示例也应该在 Windows 服务器上工作。您需要使用复制命令而不是 cp
    • “你需要使用复制命令而不是 cp”:我称之为平台相关的解决方案。仅 SFTP 的访问并不少见。特别是如果您连接到外部(例如客户或供应商的)服务器,您通常只有 SFTP 访问权限,没有 shell。
    • 实际上它是特定于平台的:是否区分大小写,特定于平台的路径分隔符。但是,如果您可以在本地执行复制,则应该在本地执行。
    • 不,SFTP 始终使用/。无论远程端是什么平台。如果您始终将文件视为区分大小写,那么区分大小写并不是真正的问题。
    【解决方案3】:

    如果原始发帖人实际上是在寻找 JSch 在两个不同 FTP 站点之间运行的工作示例,则如下:

    import com.jcraft.jsch.JSch;
    import com.jcraft.jsch.Session;
    import com.jcraft.jsch.Channel;
    import com.jcraft.jsch.ChannelSftp;
    ...
    JSch jsch = new JSch();
    JSch session = null;
    try {
      session = jsch.getSession(userid, sourceservername, sourceserverport);
      session.setPassword(sourceserverpassword);
      Properties props = new Properties();
      props.put("StrictHostKeyChecking", "no");
      session.setConfig(props);
      session.connect();
      Channel channel = session.openChannel("sftp");
      channel.connect();
      ChanelSftp channelsftp = (ChannelSftp) channel;
      channelsftp.cd(sourcefilepath);
      channelsftp.lcd(localfilepath);
      FileOutputStream fos = new FileOutputStream(new File(localfilepath + "/" + localfilename));
      channelsftp.get(sourcefilename, fos);
      fos.flush();
      fos.close();
      channelsftp.disconnect()
      session.disconnect();
    } catch (Exception e) {
      e.printStackTrace();
    }
    

    在实践中,您可能会将这些操作分解为单独的 try{}catch(){} 阻塞语句,以便引入更精细的错误报告,以及添加任何信息输出行以告知用户状态等。但是这会让你到达那里。诚然,虽然 JSch 示例比免费软件库中的大多数此类示例要好,即使是像这样的优秀示例,它们之间也可能存在一些遗漏,这些细节可能会导致或破坏您让这些东西正常工作的尝试。希望这对原始海报有所帮助,然后其他人正在寻找一个有效的 JSch 示例。一旦你让它工作了,它确实会像一个魅力,所以它是值得的。

    【讨论】:

      【解决方案4】:

      核心 SFTP 协议不支持复制远程文件。

      copy-file extension to the protocol 有一个草稿,但只有少数 SFTP 服务器(例如ProFTPD/mod_sftp 和 Bitvise SFTP 服务器)支持。

      最广泛使用的 OpenSSH SFTP 服务器(未来版本will support related copy-data)绝对不支持。

      JSch 库也不支持它。


      另见我对How can I copy/duplicate a file to another directory using SFTP?的回复


      因此,不幸的是,实际上在“exec”通道 (ChannelExec) 上使用 cp shell 命令是最好的可用方法(假设您连接到 *nix 服务器并且您具有 shell 访问权限)。


      如果您没有 shell 访问权限,那么您唯一的选择确实是将文件下载到本地临时文件夹并将其上传回新位置(或使用流,以避免临时文件)。这就是@Edwin Buck 公认的答案。

      【讨论】:

        猜你喜欢
        • 2020-09-02
        • 2014-04-16
        • 1970-01-01
        • 2013-11-21
        • 2019-09-26
        • 2011-08-11
        • 1970-01-01
        • 2010-11-11
        • 1970-01-01
        相关资源
        最近更新 更多