使用 Java 从 SSH 直接传输文件

Direct file streaming from SSH using Java

我正在用 Java Spring Boot 构建一个 api,我想做的是使用端点下载文件。问题是 api 通过 ssh 访问文件。我不希望 api 下载文件然后 return 它,我想要的是从 ssh 到响应的直接流。这可能吗?

要通过 ssh 连接并获取我正在使用 JSch 的文件。 我要下载的文件最大可达 2 GB。 谢谢


编辑: 我终于做到了,而且成功了。非常感谢 @Martin Prikryl 的帮助。

@RequestMapping(value = "/endpoint-test/download-file-stream", method = RequestMethod.GET)
@ResponseStatus(HttpStatus.OK)
public static void  sendFileInResponse (HttpServletResponse response) throws Exception {
    String path_file = "/opt/dir/file_test.txt"; //this path is inside the remote server 
    ConexionJSch new_conection_to_filesystem = new ConexionJSch(); 
    ChannelSftp channelSftp = new_conection_to_filesystem.setupJsch();
    channelSftp.connect();
            
    SftpATTRS data = channelSftp.lstat(path_file);
    long fsize = data.getSize();
    try (InputStream inputStream = channelSftp.get(path_file)){
        response.setContentType("application/octet-stream");
        response.setContentLengthLong(fsize);
        response.setHeader("Content-Disposition", "inline;filename=test.bam");
        OutputStream outputStream = response.getOutputStream() 
        byte[] buff = new byte[2048];
        int length = 0;
        while ((length = inputStream.read(buff)) > 0) {
                outputStream.write(buff, 0, length);
                outputStream.flush();
        }
        inputStream.close();
        response.setHeader("Cache-Control", "private");
        response.setDateHeader("Expires", 0);    
    } finally{
        channelSftp.exit();
    }
}
public class ConexionJSch {
    private final String remoteHost;
    private final String username;
    private final String password;

    public ConexionJSch() {
        this.remoteHost = "xxx.xxx.xxx.xxx";
        this.username = "user";
        this.password = "pass";
    }
    
    public ChannelSftp setupJsch() throws JSchException {
        JSch jsch = new JSch();
        jsch.setKnownHosts("/home/ubuntu_user/.ssh/known_hosts");
        Session jschSession = jsch.getSession(username, remoteHost);
        jschSession.setPassword(password);
        jschSession.connect();
        return (ChannelSftp) jschSession.openChannel("sftp");
    }
}

JSch 有这两个 ChannelSftp.get 重载可以帮助你:

根据您的其他问题 (),在 Spring 引导中,您使用 HttpServletResponse API 流式传输响应(文件)。结合接受OutputStreamChannelSftp.get,代码可以是:

public static void sendFileInResponse(
        HttpServletResponse response, ChannelSftp channelSftp)
        throws IOException, SftpException {
    response.setContentType("your_content_type");
    response.setHeader("Content-Disposition", "inline;filename=your_file_name");
    channelSftp.get("/path/your_file_name", response.getOutputStream());
    outputStream.close();
}

带有 OutputStream API 的变体比带有 channelSftp.get() InputStream API.

的版本短得多

虽然在 Spring Boot 上阅读了一些内容,但似乎上面的代码被阻止了,只有在 SFTP 下载完成后,客户端的下载才会有效地开始。因此,Web 服务器必须将整个文件保存在内存中。似乎更有效的解决方案是 StreamingResponseBody.