JAVA中SFTP实时上传下载

0.码仙励志

与其抱怨过去,不如认真面对未来。

1.代码实现

1.环境:

JDK1.8+SpringBoot2.3.3

2.引入依赖


    org.springframework.boot
    spring-boot-starter



    com.jcraft
    jsch
    0.1.54


    org.springframework.boot
    spring-boot-starter-logging


    org.springframework.boot
    spring-boot-configuration-processor


    org.springframework.boot
    spring-boot-starter-test
    test
    
        
            org.junit.vintage
            junit-vintage-engine
        
    

3.启动类

package com.mahaiwuji;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class FileSocketApplication {

    public static void main(String[] args) {
        SpringApplication.run(FileSocketApplication.class, args);
    }

}

4.配置文件application.yml

sftp:
  ip: 192.168.100.110
  port: 22
  username: root
  password: 'root'
  uploadSleep: 1000 #上传失败隔1秒重新上传
  uploadRettry: 10 #重新上传的次数

5.SFTP工厂类,用于获取SFTP的连接和关闭SFTP的连接

package com.mahaiwuji.sftp;

import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;

/**
 * SFTP工厂类,用于获取SFTP的连接和关闭SFTP的连接
 */
@Component
@ConfigurationProperties(prefix = "sftp")
public class SFTPConnectionFactory {
    private static Logger logger = LoggerFactory.getLogger(SFTPConnectionFactory.class);

    /**
     * SFTP 服务器地址IP地址
     */
    private static String ip;
    /**
     * SFTP 端口
     */
    private static int port;
    /**
     * SFTP 登录用户名
     */
    private static String username;
    /**
     * SFTP 登录密码
     */
    private static String password;
    /**
     * 私钥
     */
    private static String privateKey;

    private static ChannelSftp client;
    private static Session session;

    private SFTPConnectionFactory() {
    }

    /**
     * 建立连接
     *
     * @return
     */
    public synchronized static ChannelSftp makeConnection() {
        if (client == null || session == null || !client.isConnected() || !session.isConnected()) {
            try {
                JSch jsch = new JSch();
                if (privateKey != null) {
                    jsch.addIdentity(privateKey);// 设置私钥
                }
                session = jsch.getSession(username, ip, port);
                if (password != null) {
                    session.setPassword(password);
                }
                Properties config = new Properties();
                config.put("StrictHostKeyChecking", "no");
                session.setConfig(config);
                session.connect();
                Channel channel = session.openChannel("sftp");
                channel.connect();
                client = (ChannelSftp) channel;
                logger.info("sftp服务器连接成功");
            } catch (JSchException e) {
                logger.error("主机sftp登录失败,检测登录ip,端口号,用户名密码是否正确,错误信息为" + e.getMessage());
            }
        }
        return client;
    }

    /**
     * 关闭连接
     */
    public static void logout() {
        if (client != null) {
            if (client.isConnected()) {
                client.disconnect();
            }
        }
        if (session != null) {
            if (session.isConnected()) {
                session.disconnect();
            }
        }
    }

    public static String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        SFTPConnectionFactory.ip = ip;
    }

    public static int getPort() {
        return port;
    }

    public void setPort(int port) {
        SFTPConnectionFactory.port = port;
    }

    public static String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        SFTPConnectionFactory.username = username;
    }

    public static String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        SFTPConnectionFactory.password = password;
    }

    public static String getPrivateKey() {
        return privateKey;
    }

    public void setPrivateKey(String privateKey) {
        SFTPConnectionFactory.privateKey = privateKey;
    }

}

6.进度监听器

package com.mahaiwuji.sftp;

import java.text.DecimalFormat;

import com.jcraft.jsch.SftpProgressMonitor;

/**
 * 进度监听器
 */
public class FileProgressMonitor implements SftpProgressMonitor {

    private long fileSize; // 记录文件总大小

    private long transfered; // 记录已传输的数据总大小

    public FileProgressMonitor(long fileSize) {
        if (fileSize != 0) {
            this.fileSize = fileSize;
            System.out.println("数据大小: " + fileSize + " bytes");
        } else {
            System.out.println("文件错误");
        }
    }

    @Override
    public void init(int op, String src, String dest, long max) {
        System.out.println("开始");
    }

    /**
     * 实现了SftpProgressMonitor接口的count方法
     */
    @Override
    public boolean count(long count) {
        add(count);
        return true;
    }

    /**
     * 实现了SftpProgressMonitor接口的end方法
     */
    @Override
    public void end() {
        System.out.println("结束");
    }

    private synchronized void add(long count) {
        transfered = transfered + count;
        System.out.println("已传输数据大小: " + transfered + " bytes");
        double d = ((double) transfered * 100) / (double) fileSize;
        DecimalFormat df = new DecimalFormat("#.##");
        System.out.println("已传输数据占比: " + df.format(d) + "%");
    }

}

7.上传下载工具类

package com.mahaiwuji.sftp;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;

import com.jcraft.jsch.SftpATTRS;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.SftpException;

/**
 * 工具类
 */
@Component
@ConfigurationProperties(prefix = "sftp")
public class SFTPClientUtils {
    private static int uploadSleep;
    private static int uploadRettry;
    private static Logger logger = LoggerFactory.getLogger(SFTPClientUtils.class);

    private static String tempFilePath;

    /**
     * 文件上传 将文件对象上传到sftp作为文件。文件完整路径=basePath+directory 目录不存在则会上传文件夹
     *
     * @param basePath  服务器的基础路径,服务器上必须有该目录,例如 /home
     * @param directory 上传到的目录,服务器上没有会自动创建,有则不创建,例如 /test
     * @param fileIs    文件流
     * @param fileName  放到服务器上要保存的名字,例如 码海无际.txt
     * @return
     */
    public synchronized static boolean upload(String basePath, String directory, InputStream fileIs, String fileName) {
        boolean result = false;
        Integer i = 0;
        while (!result) {
            logger.info("*****开始登陆*****");
            ChannelSftp sftp = SFTPConnectionFactory.makeConnection();
            logger.info("******登陆成功*****");
            try {
                sftp.cd(basePath);
                sftp.cd(directory);
            } catch (SftpException e) {
                logger.info("sftp文件上传,目录不存在开始创建");
                String[] dirs = directory.split("/");
                String tempPath = basePath;
                for (String dir : dirs) {
                    if (null == dir || "".equals(dir)) {
                        continue;
                    }
                    tempPath += "/" + dir;
                    try {
                        sftp.cd(tempPath);
                    } catch (SftpException ex) {
                        try {
                            sftp.mkdir(tempPath);
                            sftp.cd(tempPath);
                        } catch (SftpException e1) {
                            logger.info("sftp文件上传,目录创建失败,错误信息:" + e1.fillInStackTrace());
                        }
                    }
                }
            }
            try {
                sftp.put(fileIs, fileName, new FileProgressMonitor(fileIs.available()), ChannelSftp.OVERWRITE);
                // 用下面的方法不会调用进度监控
                //sftp.put(fileIs, fileName);
                if (i > 0) {
                    logger.info("sftp重试文件上传成功,ftp路径:" + basePath + directory + ",文件名称:" + fileName);
                } else {
                    logger.info("sftp文件上传成功,ftp路径为" + basePath + directory + ",文件名称:" + fileName);
                }
                result = true;
            } catch (Exception e) {
                i++;
                logger.error("sftp文件上传失败,重试中。。。第" + i + "次,错误信息" + e.fillInStackTrace());
                if (i > uploadRettry) {
                    SFTPConnectionFactory.logout();
                    logger.error("sftp文件上传失败,超过重试次数结束重试,错误信息" + e.fillInStackTrace());
                    return result;
                }
                try {
                    TimeUnit.MILLISECONDS.sleep(uploadSleep);
                } catch (InterruptedException e1) {
                    SFTPConnectionFactory.logout();
                    e1.printStackTrace();
                    logger.error("sftp文件上传失败,系统检测出异常:" + e);
                }
            }

        }
        SFTPConnectionFactory.logout();
        logger.info("sftp上传:" + result);
        return result;
    }


    /**
     * 下载文件至本地
     *
     * @param directory    要下载文件所在目录,例如 /home
     * @param downloadFile 要下载的文件,例如 码海无际.txt
     * @param localDir     本地路径,例如 D:\\home
     * @return
     */
    public synchronized static void download(String directory, String downloadFile, String localDir) {
        logger.info("*****开始登陆*****");
        ChannelSftp sftp = SFTPConnectionFactory.makeConnection();
        logger.info("******登陆成功*****");
        if (directory != null && !"".equals(directory)) {
            try {
                sftp.cd(directory);
            } catch (SftpException e) {
                logger.error("sftp文件下载,目录不存在,错误信息" + e.fillInStackTrace());
            }
        }
        String src = directory + "/" + downloadFile;
        try {
            SftpATTRS attr = sftp.stat(src);
            long fileSize = attr.getSize();
            InputStream inputStream = sftp.get(src, new FileProgressMonitor(fileSize));
            // 用下面的方法不会调用进度监控
            //InputStream inputStream = sftp.get(src);
            String tempFile = localDir + "/" + downloadFile;
            File file = new File(tempFile);
            File fileParent = file.getParentFile();
            if (!fileParent.exists()) {
                fileParent.mkdirs();
            }
            if (!file.exists()) {
                writeToLocal(tempFile, inputStream);
            }
        } catch (SftpException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        SFTPConnectionFactory.logout();
    }

    /**
     * 将InputStream写入本地文件
     *
     * @param destination 写入本地目录
     * @param input       输入流
     * @throws IOException
     */
    public static void writeToLocal(String destination, InputStream input) throws IOException {
        int index;
        byte[] bytes = new byte[1024];
        FileOutputStream downloadFile = new FileOutputStream(destination);
        while ((index = input.read(bytes)) != -1) {
            downloadFile.write(bytes, 0, index);
            downloadFile.flush();
        }
        downloadFile.close();
        input.close();
    }

    /**
     * 删除文件
     *
     * @param directory  要删除文件所在目录,例如 /home
     * @param deleteFile 要删除的文件,例如 码海无际.txt
     */
    public synchronized static boolean delete(String directory, String deleteFile) {
        boolean result = false;
        ChannelSftp sftp = SFTPConnectionFactory.makeConnection();
        try {
            sftp.cd(directory);
            sftp.rm(deleteFile);
        } catch (SftpException e) {
            e.printStackTrace();
        }
        result = true;
        SFTPConnectionFactory.logout();
        return result;
    }

    public static int getUploadSleep() {
        return uploadSleep;
    }

    public void setUploadSleep(int uploadSleep) {
        SFTPClientUtils.uploadSleep = uploadSleep;
    }

    public static int getUploadRettry() {
        return uploadRettry;
    }

    public void setUploadRettry(int uploadRettry) {
        SFTPClientUtils.uploadRettry = uploadRettry;
    }

    public static String getTempFilePath() {
        return tempFilePath;
    }

    public void setTempFilePath(String tempFilePath) {
        SFTPClientUtils.tempFilePath = tempFilePath;
    }

}

8.测试类

package com.mahaiwuji.file;

import com.mahaiwuji.sftp.SFTPClientUtils;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.*;

@SpringBootTest
class FileTest {

    /**
     * 上传
     *
     * @throws FileNotFoundException
     */
    @Test
    void uploadTest() throws FileNotFoundException {
        String src = "D:\\home\\360zip_setup_4.0.0.1200.exe"; // 本地文件名
        File file = new File(src);
        SFTPClientUtils.upload("/home", "/aa", new FileInputStream(file), "360zip_setup_4.0.0.1200.exe");
    }

    /**
     * 下载
     */
    @Test
    void downloadTest() {
        SFTPClientUtils.download("/home/aa", "360zip_setup_4.0.0.1200.exe", "D:\\home");
    }

    /**
     * 删除
     */
    @Test
    void deleteTest() {
        SFTPClientUtils.delete("/home/aa", "360zip_setup_4.0.0.1200.exe");
    }
}

9.参考文献

https://www.cnblogs.com/longyg/archive/2012/06/25/2556576.html

https://www.cnblogs.com/longyg/archive/2012/06/25/2561332.html

你可能感兴趣的:(Javase)