当前位置:首页 > 技术 > 正文内容

使用Java通过SFTP管理远程Linux服务器文件

访客 技术 2026年7月8日 1

基于JSch实现安全文件传输操作

在分布式系统开发中,经常需要与远程Linux服务器进行安全的文件交互。SFTP(SSH File Transfer Protocol)基于SSH协议提供加密的数据传输,是替代传统FTP的安全选择。本文介绍如何使用Java结合JSch库完成常见的远程文件操作,包括目录浏览、文件上传下载、删除以及以字节数组形式获取文件内容。

Maven依赖配置

项目需引入JSch用于SFTP通信,同时使用Apache Commons IO简化流处理:

<properties>
    <jsch.version>0.1.55</jsch.version>
    <commons-io.version>2.16.1</commons-io.version>
</properties>

<dependencies>
    <dependency>
        <groupId>com.jcraft</groupId>
        <artifactId>jsch</artifactId>
        <version>${jsch.version}</version>
    </dependency>
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>${commons-io.version}</version>
    </dependency>
</dependencies>

SFTP客户端工具类实现

封装一个可复用的SFTP工具类,支持密码和私钥两种认证方式,并提供常用文件操作接口。

import com.jcraft.jsch.*;
import org.apache.commons.io.IOUtils;

import java.io.*;
import java.util.Properties;
import java.util.Vector;

public class SecureFileTransferClient {

    private ChannelSftp channel;
    private Session sshSession;
    private final String host;
    private final int port;
    private final String username;
    private final String password;
    private final String privateKeyPath;

    // 密码认证构造函数
    public SecureFileTransferClient(String username, String password, String host, int port) {
        this(username, host, port, password, null);
    }

    // 私钥认证构造函数
    public SecureFileTransferClient(String username, String host, int port, String privateKeyPath) {
        this(username, host, port, null, privateKeyPath);
    }

    private SecureFileTransferClient(String username, String host, int port, String password, String privateKeyPath) {
        this.username = username;
        this.host = host;
        this.port = port;
        this.password = password;
        this.privateKeyPath = privateKeyPath;
    }

    /**
     * 建立SFTP连接
     */
    public void connect() throws JSchException {
        JSch jsch = new JSch();
        if (privateKeyPath != null) {
            jsch.addIdentity(privateKeyPath);
        }

        sshSession = jsch.getSession(username, host, port);
        if (password != null) {
            sshSession.setPassword(password);
        }

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

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

    /**
     * 断开连接
     */
    public void disconnect() {
        if (channel != null && channel.isConnected()) {
            channel.disconnect();
        }
        if (sshSession != null && sshSession.isConnected()) {
            sshSession.disconnect();
        }
    }

    /**
     * 获取指定路径下的文件列表
     */
    public Vector<LsEntry> listDirectory(String path) throws SftpException {
        return channel.ls(path);
    }

    /**
     * 删除远程文件
     */
    public void removeFile(String remoteDir, String filename) throws SftpException {
        channel.cd(remoteDir);
        channel.rm(filename);
    }

    /**
     * 上传输入流为远程文件,自动创建缺失目录
     */
    public void uploadStream(String basePath, String targetDir, String remoteName, InputStream input)
            throws SftpException {
        try {
            channel.cd(basePath);
            ensureRemoteDirectoryExists(targetDir);
            channel.put(input, remoteName);
        } catch (SftpException e) {
            throw new SftpException(e.id, "Upload failed: " + e.getMessage());
        }
    }

    private void ensureRemoteDirectoryExists(String dirPath) throws SftpException {
        String[] segments = dirPath.split("/");
        StringBuilder currentPath = new StringBuilder();

        for (String segment : segments) {
            if (segment.isEmpty()) continue;
            currentPath.append("/").append(segment);
            try {
                channel.cd(currentPath.toString());
            } catch (SftpException ex) {
                channel.mkdir(currentPath.toString());
                channel.cd(currentPath.toString());
            }
        }
    }

    /**
     * 下载文件到本地磁盘
     */
    public void downloadToFile(String remoteDir, String filename, String localPath)
            throws SftpException, FileNotFoundException {
        if (remoteDir != null && !remoteDir.trim().isEmpty()) {
            channel.cd(remoteDir);
        }
        channel.get(filename, localPath);
    }

    /**
     * 下载文件并返回字节数组
     */
    public byte[] downloadAsBytes(String remoteDir, String filename) throws IOException, SftpException {
        if (remoteDir != null && !remoteDir.trim().isEmpty()) {
            channel.cd(remoteDir);
        }
        try (InputStream inputStream = channel.get(filename)) {
            return IOUtils.toByteArray(inputStream);
        }
    }

    // 使用示例
    public static void main(String[] args) {
        SecureFileTransferClient client = new SecureFileTransferClient(
                "yourUsername", "yourPassword", "192.168.1.100", 22);

        try {
            client.connect();

            // 1. 列出/home/yourUsername目录内容
            Vector<LsEntry> files = client.listDirectory("/home/yourUsername");
            for (LsEntry entry : files) {
                System.out.println("File: " + entry.getFilename());
            }

            // 2. 删除 test.txt 文件
            client.removeFile("/home/yourUsername", "test.txt");

            // 3. 上传本地文件
            File source = new File("C:\\local\\data.txt");
            try (FileInputStream fis = new FileInputStream(source)) {
                client.uploadStream("/home/yourUsername", "uploads/temp", "uploaded.txt", fis);
            }

            // 4. 下载文件到本地
            client.downloadToFile("/home/yourUsername/uploads", "uploaded.txt", "C:\\local\\downloaded.txt");

            // 5. 以字节数组形式获取文件
            byte[] data = client.downloadAsBytes("/home/yourUsername", "report.log");
            System.out.println("Downloaded " + data.length + " bytes.");

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            client.disconnect();
        }
    }
}

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。