java 链接SFTP并进行文件操作

最近做关于对账文件的项目,就是约定第三方将对账文件放至SFTP服务器上,然后我将加密后的SFTP文件拿到、解密、然后发送邮件给需要的人。

关于发送邮件在上一篇已经说过了不多赘述https://www.cnblogs.com/yangchengdebokeyuan/p/14812179.html

关于SFTP操作我自己总结的其实就是长时间对一个文件服务器进行操作,其中大致分为三个步骤 登录服务器(建立连接)、操作文件及逻辑处理、登出(关闭连接)

其实我除了操作文件的逻辑以及服务器不同之外用的全是同事之前写的SFTP工具类,所以此篇逻辑部分只能作为参考并不能直接引用。

一、建立链接&断开链接

  其实就是调用util类的方法就行了,因为项(zi)目(ji)急(lan)就没做过多了解,有兴趣的小伙伴可以了解下_(:з」∠)_

  

import com.jcraft.jsch.*;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;

import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class SftpUtils {

    @Value("${FTP-HOST}")
    private String sftpHost;


    @Value("${FTP-PORT}")
    private Integer sftpPort;


    @Value("${FTP-USERNAME}")
    private String username;


    @Value("${FTP-PASSWORD}")
    private String password;

    private ChannelSftp sftp;
    private Session session;

    private static Logger logger = LoggerFactory.getLogger(SftpUtils.class);

    protected final static int CLIENT_TIMEOUT = 1000 * 180;

    public SftpUtils(String username, String password, String sftpHost, int sftpPort) {
        this.username = username;
        this.password = password;
        this.sftpHost = sftpHost;
        this.sftpPort = sftpPort;
    }

    public SftpUtils() {
    }

    public void login() {
        try {
            JSch jsch = new JSch();

            session = jsch.getSession(username, sftpHost, sftpPort);
            session.setTimeout(CLIENT_TIMEOUT);
            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();

            sftp = (ChannelSftp) channel;
            if (sftp != null) {
                logger.debug("SftpUtils-sftpHost:{},sftpPort:{},username:{},password:{},success", sftpHost, sftpPort, username, password);
            } else {
                logger.debug("SftpUtils-sftpHost:{},sftpPort:{},username:{},password:{},faild", sftpHost, sftpPort, username, password);
            }
        } catch (Exception e) {
            logout();
            e.printStackTrace();
            logger.debug("login" + e);
        }
    }

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

    /**
     * 将输入流的数据上传到sftp作为文件。文件完整路径=basePath+directory
     *
     * @param directory    上传到该目录
     * @param sftpFileName sftp端文件名
     */
    public boolean upload(String directory, String sftpFileName, InputStream input) {
        try {
            if (directory != null && !"".equals(directory)) {
                sftp.cd(directory);
            }
            sftp.put(input, sftpFileName);  //上传文件
            return true;
        } catch (SftpException e) {
            e.printStackTrace();
            return false;
        }
    }

    public InputStream readFile(String ftpPath) {
        InputStream inputStream = null;
        try {
            inputStream = sftp.get(ftpPath);
        } catch (Exception e) {
            e.printStackTrace();
            logger.info("readFile error.");
        }
        return inputStream;
    }

    public static int compress(List<String> filePaths, String zipFilePath, Boolean keepDirStructure) throws IOException {
        byte[] buf = new byte[1024];
        File zipFile = new File(zipFilePath);
        //zip文件不存在,则创建文件,用于压缩
        if (!zipFile.exists())
            zipFile.createNewFile();
        int fileCount = 0;//记录压缩了几个文件?
        try {
            ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile));
            for (int i = 0; i < filePaths.size(); i++) {
                String relativePath = filePaths.get(i);
                if (StringUtils.isEmpty(relativePath)) {
                    continue;
                }
                File sourceFile = new File(relativePath);//绝对路径找到file
                if (sourceFile == null || !sourceFile.exists()) {
                    continue;
                }
                FileInputStream fis = new FileInputStream(sourceFile);
                if (keepDirStructure != null && keepDirStructure) {
                    //保持目录结构
                    zos.putNextEntry(new ZipEntry(relativePath));
                } else {
                    //直接放到压缩包的根目录
                    zos.putNextEntry(new ZipEntry(sourceFile.getName()));
                }
                //System.out.println("压缩当前文件:"+sourceFile.getName());
                int len;
                while ((len = fis.read(buf)) > 0) {
                    zos.write(buf, 0, len);
                }
                zos.closeEntry();
                fis.close();
                fileCount++;
            }

            zos.close();
            logger.debug("压缩完成");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return fileCount;
    }

    /**
     * 更换文件名
     * [oldFileName, newfileName]
     *
     * @return boolean
     * 
     * @date 2020/10/20 16:10
     */
    public boolean renameFile(String oldFileName, String newfileName) {
        boolean flag = false;
        if (sftp != null) {
            try {
                sftp.rename(oldFileName, newfileName);
                flag = true;
            } catch (Exception e) {
                logger.error("更换文件名--ERROR:" + e);
                flag = false;
            }
        }
        return flag;
    }

    /**
     * 读取ftp目录下全部文件夹
     * [directory]
     *
     * @return java.util.Vector
     * 
     * @date 2020/10/21 9:28
     */
    public Vector listFiles(String directory) throws SftpException {
        return sftp.ls(directory);
    }

    /**
     * 文件夹是否存在
     * [directory]
     *
     * @return boolean
     * 
     * @date 2020/10/21 16:47
     */
    public boolean isDirExist(String directory) {
        boolean isDirExistFlag = false;
        try {
            SftpATTRS sftpATTRS = sftp.lstat(directory);
            isDirExistFlag = true;
            return sftpATTRS.isDir();
        } catch (Exception e) {
            if (e.getMessage().toLowerCase().equals("no such file")) {
                isDirExistFlag = false;
            }
            logger.debug("isDirExist:" + e);
        }
        return isDirExistFlag;
    }

    /**
     * 删除文件
     * [oldFileName, newfileName]
     *
     * @return boolean
     *
     * @date 2020/10/22 9:54
     */
    public boolean delete(String directory, String deleteFile) throws Exception {
        boolean flag = false;
        if (sftp != null) {
            try {
                sftp.cd(directory);
                sftp.rm(deleteFile);
                flag = true;
            } catch (Exception e) {
                logger.error("删除文件夹--ERROR:" + e);
                flag = false;
            }
        }
        return flag;
    }

    /**
     * 创建该文件夹
     * [createpath]
     *
     * @return void
     *
     * @date 2020/10/21 16:53
     */
    public void createDir(String createpath) {
        try {
            if (isDirExist(createpath)) {
                this.sftp.cd(createpath);
                return;
            }
            String pathArry[] = createpath.split("/");
            StringBuffer filePath = new StringBuffer("/");
            for (String path : pathArry) {
                if (path.equals("")) {
                    continue;
                }
                filePath.append(path + "/");
                if (isDirExist(filePath.toString())) {
                    sftp.cd(filePath.toString());
                } else {
                    // 建立目录
                    sftp.mkdir(filePath.toString());
                    // 进入并设置为当前目录
                    sftp.cd(filePath.toString());
                }
            }
            this.sftp.cd(createpath);
        } catch (SftpException e) {
            logger.error("创建路径错误:" + createpath);
        }
    }


    public static void main(String[] args) {
//        SftpUtils sftp1 = new SftpUtils("sftptest", "xxxxx", "172.30.xx.xxx", 443);
//        sftp1.login();
//        ChannelSftp sftp = new ChannelSftp();
//        if (sftp != null) {
//            try {
//                sftp.rename("/home/sftptest/TEST/xxx094300.csv", "/home/sftptest/TEST/xxxx094300.csv");
//            } catch (Exception e) {
//                logger.error("更换文件名--ERROR:" + e);
//            }
//        }

    }

}
View Code

二、文件处理

  1.文件操作及逻辑处理都会放出来但是解密部分就不放出来了,见谅~

   

package com.allianz.quartzjob.util;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/***
 *
 * @author y.c
 * @date 2021-05-25 10:40:59
 *
 */
public class TxtUtils {
    private static Logger logger = LoggerFactory.getLogger(TxtUtils.class);
    public static PsbcMerchantMain psbcUtils = new PsbcMerchantMain();

    public static List showTxt(String path, String filename) {
        String filePath = path+"/"+filename;
        FileInputStream fileInputStream = null;
        InputStreamReader fie = null;
        BufferedReader by =null;
        List list = null;
        try {
            fileInputStream = new FileInputStream(filePath);
            fie = new InputStreamReader(fileInputStream,"UTF-8");
            by = new BufferedReader(fie);
            String line = "";
            list = new ArrayList();
            while((line=by.readLine())!= null){
                list.add(line);
            }
            fileInputStream.close();
            fie.close();
            by.close();
        } catch (IOException e) {
            e.printStackTrace();
        }catch(Exception e){
            e.printStackTrace();
        }finally {

            if (null!=fileInputStream){
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null!=fie){
                try {
                    fie.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null!=by){
                try {
                    by.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
        return list;
    }
    public static List showPSBCTxt(InputStream inputStream) {
        InputStreamReader fie = null;
        BufferedReader by =null;
        List list = null;
        try {
            fie = new InputStreamReader(inputStream,"UTF-8");
            by = new BufferedReader(fie);
            String line = "";
            list = new ArrayList();
            int i = 0;
            while((line=by.readLine())!= null){
                logger.error(line.toString());
                //第一行为总条数不参与解密
                if (i>0){
                    try {
                        line = psbcUtils.PSBCdecrypt(line);
                    } catch (Exception e) {
                        logger.error("PSBC 解密失败》》》 "+line);
                        line = null;
                    }
                }
                i++;
                list.add(line);
            }
            logger.error(">>>>>>>>解密结果:"+list.toString());
            inputStream.close();
            fie.close();
            by.close();
        } catch (IOException e) {
            e.printStackTrace();
        }catch(Exception e){
            e.printStackTrace();
        }finally {

            if (null != inputStream) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != fie) {
                try {
                    fie.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != by) {
                try {
                    by.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
        return list;
    }

    public static void main(String[] args) {
        String path="D:\Desktop\";
        String name="99360000007_EL_CHECK_ACCOUNT_0000000004_0000_20210522_A_0001_0001.txt";
        List list = showTxt(path,name);
        List listNew = new ArrayList();
        PsbcMerchantMain psbcUtils = new  PsbcMerchantMain();
        logger.error(">>>>>>>List:"+list);
        list.size();
        int countList=0;
        String decStr =null;
        if (null!=list&&list.size()>0){
            countList = Integer.valueOf(list.get(0).toString());
            for (int i = 0; i <list.size() ; i++) {
                if (i==0){
                    listNew.add(String.valueOf(countList));
                    continue;//第一行不用解密
                }
                String str = list.get(i).toString();
                System.out.println(i+">>>>>>>> 解密 i:"+str);
                //解密
                try {
                   decStr = psbcUtils.PSBCdecrypt(str);
                } catch (Exception e) {
                    logger.error("PSBC 解密失败》》》 "+i);
                    decStr = null;
                }
                System.out.println(">>>>>>>>解密结果:"+decStr);

                listNew.add(decStr);
            }

        }
//        System.out.println(showTxt(path,name));
        logger.error(">>>>>>>listNew:"+listNew.toString());
        boolean a =listNew.size()>0?writeDataHubData(listNew,"","对账文件"):false;
        logger.error("生成结果:"+a);
    }

    public static boolean writeDataHubData(List<String> result,String path, String fileName) {
        long start = System.currentTimeMillis();
        String filePath = null;
        filePath = "D:\Desktop\txt\";
        StringBuffer content = new StringBuffer();
        boolean flag = false;
        BufferedWriter out = null;
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            String dateStr = sdf.format(new Date());
            if (result != null && !result.isEmpty() && StringUtils.isNotEmpty(fileName)) {
                File pathFile = new File(filePath);
                if(!pathFile.exists()){
                    pathFile.mkdirs();
                }
                String relFilePath = filePath + fileName;
                File file = new File(relFilePath);
                if (!file.exists()) {
                    file.createNewFile();
                }
                out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"));
                for (String info : result) {

                    out.write(info);
                    out.newLine();
                }
                flag = true;
                logger.info("写入文件耗时:*********************************" + (System.currentTimeMillis() - start) + "毫秒");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }catch(Exception e){
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.flush();
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return flag;
        }
    }
    /***
     * 将list存入服务器
     * @author y.c
     * @date 2021-05-25 18:31:04
     *
     */
    public static boolean saveTXT(List<String> result ,String path, String fileName) {
        long start = System.currentTimeMillis();
        String filePath = path;
        StringBuffer content = new StringBuffer();
        boolean flag = false;
        BufferedWriter out = null;
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            String dateStr = sdf.format(new Date());
            if (result != null && !result.isEmpty() && StringUtils.isNotEmpty(fileName)) {
                fileName += "_" + dateStr + ".txt";
                File pathFile = new File(filePath);
                if(!pathFile.exists()){
                    pathFile.mkdirs();
                }
                String relFilePath = filePath + fileName;
                File file = new File(relFilePath);
                if (!file.exists()) {
                    file.createNewFile();
                }
                out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"));
                for (String info : result) {

                    out.write(info);
                    out.newLine();
                }
                flag = true;
                logger.info("写入文件耗时:*********************************" + (System.currentTimeMillis() - start) + "毫秒");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }catch(Exception e){
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.flush();
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return flag;
        }
    }

    public static String getDateFloderName() throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateStr = sdf.format(new Date());
        Date date = sdf.parse(dateStr);
        if (date != null) {
            Calendar c = Calendar.getInstance();
            c.setTime(date);
            int year = c.get(Calendar.YEAR);
            int month = c.get(Calendar.MONTH) + 1;
            int dateNow = c.get(Calendar.DATE);
            String folderName = year + "/" + month + "/" + dateNow + "/";
            return folderName;
        } else {
            return "";
        }
    }
    public static String getPCDateFloderName() throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateStr = sdf.format(new Date());
        Date date = sdf.parse(dateStr);
        if (date != null) {
            Calendar c = Calendar.getInstance();
            c.setTime(date);
            int year = c.get(Calendar.YEAR);
            int month = c.get(Calendar.MONTH) + 1;
            int dateNow = c.get(Calendar.DATE);
            String folderName = year + "\" + month + "\" + dateNow + "\";
            return folderName;
        } else {
            return "";
        }
    }

    public static String getNowDate(){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String dateStr = sdf.format(new Date());
        return dateStr;
    }
}
TxtUtils

  2.业务逻辑

import com.allianz.quartzjob.entity.psbc.FtpEntity;
import com.allianz.quartzjob.service.PSBCService;
import com.allianz.quartzjob.util.MailUtil;
import com.allianz.quartzjob.util.SftpUtils;
import com.allianz.quartzjob.util.TxtUtils;
import com.jcraft.jsch.ChannelSftp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.text.ParseException;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

public class ReadPsbcThread implements Runnable {

    private static Logger logger = LoggerFactory.getLogger(ReadPsbcThread.class);
    public  static TxtUtils txtUtils = new TxtUtils();

    private FtpEntity psbcFtp;
    private PSBCService psbcService;
    public ReadPsbcThread(FtpEntity psbcFtp,PSBCService psbcService) {
        this.psbcFtp=psbcFtp;
        this.psbcService=psbcService;
    }

    @Override
    public void run() {
        logger.info("ReadPsbcThread>>>>>>--start!");
        String logMsg = "SFTP初始化失败...";
        String tmpPathName="/tmp";
        SftpUtils sftp = null;
        try {
            //连接SFTP
            sftp = new SftpUtils( psbcFtp.getPSBC_FTP_USERNAME(),
                                            psbcFtp.getPSBC_FTP_PASSWORD(),
                                            psbcFtp.getPSBC_FTP_HOST(),
                                            psbcFtp.getPSBC_FTP_PORT());
            logMsg = "SFTP登录失败...";
            sftp.login();
            //在文件服务器上检索文件
            String ftpUnReadPath =psbcFtp.getPSBC_FILE_UNREADFILE();
            //读取目录路径下全部文件
            Vector vector = sftp.listFiles(ftpUnReadPath);
            if (vector.size() > 0) {
                Iterator iterator = vector.iterator();
                while (iterator.hasNext()) {
                    ChannelSftp.LsEntry entry = (ChannelSftp.LsEntry) iterator.next();
                    String UnReadFileNamePsbc = entry.getFilename();
                    logMsg = "SFTP未找到TXT文件..."+psbcFtp.getPSBC_FILE_UNREADFILE();
                    //判断是否有txt文件
                    if (UnReadFileNamePsbc.contains(".txt")) {
                        logger.info("Read---PSBC文件名:" + UnReadFileNamePsbc);
                        logger.info("Read---PSBC文件名:" + ftpUnReadPath + UnReadFileNamePsbc);
                        logMsg = "SFTP 读取TXT文件失败..."+ftpUnReadPath + UnReadFileNamePsbc;
                        InputStream inputStream = sftp.readFile(ftpUnReadPath + UnReadFileNamePsbc);
                        if (null != inputStream) {
                            //获取明文list//读取内容并解密
                            List list = txtUtils.showPSBCTxt(inputStream);
                            logger.error("SFTP 读取TXT文件list..."+list.toString());
                            // 先将保存到本地
                            String localPath =psbcFtp.getPSBC_FILE_TMP();
                            //boolean saveStatus = txtUtils.saveTXT(list,localPath,readFileNamePsbc);
                            boolean saveStatus = txtUtils.writeDataHubData(list,localPath,UnReadFileNamePsbc);
                            logger.error("先将解密后文件保存到本地:"+saveStatus);
                            if (!saveStatus){
                                logMsg = "SFTP 将解密后文件保存到本地失败..."+saveStatus;
                                continue;
                            }
                            logMsg= "SFTP 文件保存到本地成功保存!解密后的文件到SFTP服务器失败..."+saveStatus;
                            // 保存解密后的文件到SFTP服务器
                            String readFilePath=psbcFtp.getPSBC_FILE_READFILE();
                            try {
                                readFilePath = readFilePath+txtUtils.getDateFloderName();
                                sftp.createDir(readFilePath);
                            } catch (ParseException e) {
                                logger.error("获取路径失败..."+readFilePath);
                            }
                            FileInputStream fos = new FileInputStream(new File(localPath+UnReadFileNamePsbc));
                            saveStatus = sftp.upload(readFilePath, UnReadFileNamePsbc, fos);
                            if (!saveStatus){
                                logMsg= "SFTP 文件保存到本地成功!保存解密后的文件到SFTP服务器失败..."+saveStatus;
                                continue;
                            }
                            logMsg= "SFTP 解密文件操作成功源文件移动失败..."+saveStatus;
                            // 再将源文件移动至已处理文件夹
                            String uploadFileUrl = ftpUnReadPath + txtUtils.getDateFloderName()+UnReadFileNamePsbc;
                            sftp.createDir(ftpUnReadPath + txtUtils.getDateFloderName());
                            //移除读取文件
                            saveStatus = sftp.renameFile(ftpUnReadPath + UnReadFileNamePsbc, uploadFileUrl);
                            if (!saveStatus){
                                logMsg= "SFTP 解密文件操作成功源文件移动失败..."+saveStatus;
                                continue;
                            }
                            logMsg= "SFTP 文件操作成功发送邮件失败..."+saveStatus;
                            //文件操作成功发送邮件
                            String mailHost=psbcFtp.getPSBC_MAIL_HOST();
                            String senderUsername=psbcFtp.getPSBC_MAIL_SENDER();
                            MailUtil se = new MailUtil(false,mailHost,senderUsername);
                            File affix = new File(localPath+UnReadFileNamePsbc);
                            String subject="PSBC对账文件-"+txtUtils.getNowDate();
                            String sendHtml="今日份对账文件如附件,请查收~~~";
                            String receiveUser=psbcFtp.getPSBC_MAIL_RECIPIENT();
                            boolean status = se.doSendEmail(subject, sendHtml, receiveUser, affix);//

                            logMsg= "SFTP 文件操作成功发送邮件成功..."+status;
                        }
                    }
                }
            }
            sftp.logout();
        } catch (Exception e) {
            logger.error(logMsg);
            e.printStackTrace();
        }finally {
            if (sftp != null){
                sftp.logout();
            }
        }

        logger.info("ReadPsbcThread>>>>>>" + tmpPathName + "--End!"+logMsg);
    }
}
ReadTXTThread

  3.实体

  

import lombok.Data;

@Data
public class FtpEntity {
    private String PSBC_FTP_USERNAME;//ftp用户名
    private String PSBC_FTP_PASSWORD;//ftp密码
    private String PSBC_FTP_HOST;//ftp IP
    private int    PSBC_FTP_PORT;//ftp 端口

    private String PSBC_MAIL_HOST;//邮箱smtp服务器
    private String PSBC_MAIL_AUTH;
    private String PSBC_MAIL_SENDER;//邮件发件人
    private String PSBC_MAIL_RECIPIENT;//邮件收件人(多个用;隔开)

    private String PSBC_FILE_UNREADFILE;//解密前文件地址
    private String PSBC_FILE_READFILE;//解密后文件地址
    private String PSBC_FILE_TMP;//解密后文件临时存放地址
}
FtpEntity

  仅供参考哈~~~

原文地址:https://www.cnblogs.com/yangchengdebokeyuan/p/14812210.html