001package top.cenze.utils;
002
003import cn.hutool.core.util.ObjectUtil;
004import cn.hutool.core.util.StrUtil;
005import com.jcraft.jsch.*;
006import lombok.SneakyThrows;
007
008import java.io.File;
009import java.io.InputStream;
010import java.io.OutputStream;
011import java.util.Properties;
012import java.util.Vector;
013
014/**
015 * 文件传输工具
016 *
017 * @author chengze
018 * @date 2023-11-14 22:27
019 */
020public class SFTPUtil {
021
022    protected final static int CLIENT_TIMEOUT = 1000 * 180;
023    private static ChannelSftp sftp = null;
024    private static String username = null;
025    private static String password = null;
026    private static String host = null;
027    private static Integer port = null;
028    private static String privateKey = null;
029
030    public SFTPUtil(){
031    }
032
033    /**
034     * 连接Sftp服务器(基于用户名密码)
035     */
036    public static void login(String _username, String _password, String _host, int _port) {
037        username = _username;
038        password = _password;
039        host = _host;
040        port = _port;
041
042        login();
043    }
044
045    /**
046     * 连接Sftp服务器(基于用户名密钥)
047     */
048    public static void login(String _username, String _host, int _port, String _privateKey) {
049        username = _username;
050        host = _host;
051        port = _port;
052        privateKey = _privateKey;
053
054        login();
055    }
056
057    private static void login() {
058        if (StrUtil.isEmpty(username) || StrUtil.isEmpty(host) || ObjectUtil.isNull(port)) {
059            throw new RuntimeException("登录信息不能为空");
060        }
061
062        try {
063            JSch jSch = new JSch();
064
065            Session session = jSch.getSession(username, host, port);
066            session.setTimeout(CLIENT_TIMEOUT);
067            if (StrUtil.isNotEmpty(privateKey)) {
068                jSch.addIdentity(privateKey);   // 设置密钥
069            } else if (StrUtil.isNotEmpty(password)) {
070                session.setPassword(password);
071            }
072
073            Properties config = new Properties();
074            config.put("StrictHostKeyChecking", "no");
075
076            session.setConfig(config);
077            session.connect();
078
079            Channel channel = session.openChannel("sftp");
080            channel.connect();
081            sftp = (ChannelSftp) channel;
082        } catch (JSchException e) {
083            throw new RuntimeException("登录SFTP异常:" + e.getMessage());
084        }
085    }
086
087    /**
088     * 关闭连接 server
089     */
090    @SneakyThrows
091    public static void logout(){
092        if (ObjectUtil.isNotNull(sftp)) {
093            if (sftp.isConnected()) {
094                sftp.disconnect();
095            }
096        }
097        if (ObjectUtil.isNotNull(sftp.getSession())) {
098            if (sftp.getSession().isConnected()) {
099                sftp.getSession().disconnect();
100            }
101        }
102    }
103
104    /**
105     * 将输入流的数据上传到Sftp作为文件。文件完整路径=basePath+directory
106     * @param dirPath  服务器的基础路径(目录)
107     * @param sftpFileName  Sftp端文件名
108     */
109    public static boolean upload(String dirPath, String sftpFileName, InputStream input) {
110        boolean success = false;
111
112        if (ObjectUtil.isNull(sftp) || !sftp.isConnected()) {
113            login();
114        }
115
116        try {
117            sftp.cd(dirPath);
118        } catch (SftpException e) {
119            //目录不存在,则创建文件夹
120            String [] dirs = dirPath.split("/");
121            String tempPath = "";
122            for(String dir:dirs){
123                if(null== dir || "".equals(dir)) {
124                    continue;
125                }
126                tempPath+="/"+dir;
127                try {
128                    sftp.cd(tempPath);
129                } catch (SftpException O1) {
130                    try {
131                        sftp.mkdir(tempPath);
132                        sftp.cd(tempPath);
133                    } catch (SftpException e2) {
134                    }
135                }
136                try{
137                    sftp.cd(tempPath);
138                }catch(SftpException O1){
139                }
140            }
141        }
142        try {
143            //上传文件
144            sftp.put(input, sftpFileName);
145        } catch (SftpException e) {
146            // TODO Auto-generated catch block
147            success = false;
148        } finally {
149            logout();
150        }
151        return success;
152    }
153
154    /**
155     * 下载文件。
156     */
157    public static boolean download(String host, int port, String username, String password, String filePath, final OutputStream outputStream) {
158        boolean downloaded = true;
159        String fileName = null;
160
161        if (ObjectUtil.isNull(sftp) || !sftp.isConnected()) {
162            login();
163        }
164
165        try {
166            if (filePath != null && !"".equals(filePath)) {
167                String directory = filePath.substring(0, filePath.lastIndexOf(File.separator));
168                sftp.cd(directory);
169            }
170            fileName = filePath.substring(filePath.lastIndexOf(File.separator) + 1);
171
172            sftp.get(fileName, outputStream);
173        } catch (SftpException e) {
174            downloaded = false;
175        } finally {
176            logout();
177        }
178        return downloaded;
179    }
180
181    /**
182     * 删除文件
183     */
184    public static boolean delete(String filePath){
185        boolean success = true;
186
187        if (ObjectUtil.isNull(sftp) || !sftp.isConnected()) {
188            login();
189        }
190
191        try {
192            String directory = filePath.substring(0, filePath.lastIndexOf(File.separator));
193            sftp.cd(directory);
194            String fileName = filePath.substring(filePath.lastIndexOf(File.separator) + 1);
195            sftp.rm(fileName);
196        } catch (SftpException e) {
197            success = false;
198        } finally {
199            logout();
200        }
201        return success;
202    }
203
204    /**
205     * 列出目录下的文件
206     */
207    public static boolean isFileExist(String host, int port, String username, String password, String filePath) {
208        boolean success = false;
209
210        if (ObjectUtil.isNull(sftp) || !sftp.isConnected()) {
211            login();
212        }
213
214        try {
215            String directory = filePath.substring(0, filePath.lastIndexOf(File.separator));
216            String fileName = filePath.substring(filePath.lastIndexOf(File.separator) + 1);
217            Vector<?> vector = sftp.ls(directory);
218            for (Object obj : vector) {
219                if (obj != null) {
220                    ChannelSftp.LsEntry lsEntry = (ChannelSftp.LsEntry) obj;
221                    if (fileName.equals(lsEntry.getFilename())) {
222                        success = true;
223                        break;
224                    }
225                }
226            }
227        } catch (Exception e) {
228        } finally {
229            logout();
230        }
231        return success;
232    }
233}