sftp 工具类


import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Vector;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.ChannelSftp.LsEntry;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import com.ninefbank.smallpay.common.util.SpringContextHolder;
import com.ninefbank.smallpay.merchant.web.common.MerchantWebSetting;

/**
* 利用JSch包实现SFTP下载、上传文件的类
*
* @version 1.0
*/
public class SftpUtil {
private static final Logger logger = LoggerFactory.getLogger(SftpUtil.class);
public static final String SFTP_PROTOCAL = "sftp";

/**
* Password authorization
*
* @param host
* 主机IP
* @param username
* 主机登陆用户名
* @param password
* 主机登陆密码
* @param port
* 主机ssh登陆端口,如果port <= 0取默认值(22)
* @return sftp
* @throws Exception
* @see http://www.jcraft.com/jsch/
*/
public static ChannelSftp connect(String host, String username, String password, int port) throws Exception {
Channel channel = null;
ChannelSftp sftp = null;
JSch jsch = new JSch();

Session session = createSession(jsch, host, username, port);
// 设置登陆主机的密码
session.setPassword(password);
// 设置登陆超时时间
session.connect(15000);
logger.info("Session connected to " + host + ".");
try {
// 创建sftp通信通道
channel = (Channel) session.openChannel(SFTP_PROTOCAL);
channel.connect(1000);
logger.info("Channel created to " + host + ".");
sftp = (ChannelSftp) channel;
} catch (JSchException e) {
logger.error("exception when channel create.", e);
}
return sftp;
}

/**
* Private/public key authorization (加密秘钥方式登陆)
*
* @param username
* 主机登陆用户名(user account)
* @param host
* 主机IP(server host)
* @param port
* 主机ssh登陆端口(ssh port), 如果port<=0, 取默认值22
* @param privateKey
* 秘钥文件路径(the path of key file.)
* @param passphrase
* 密钥的密码(the password of key file.)
* @return sftp
* @throws Exception
* @see http://www.jcraft.com/jsch/
*/
public static ChannelSftp connect(String username, String host, int port, String privateKey, String passphrase)
throws Exception {
Channel channel = null;
ChannelSftp sftp = null;
JSch jsch = new JSch();

// 设置密钥和密码 ,支持密钥的方式登陆
if (StringUtils.isNotEmpty(privateKey)) {
if (StringUtils.isNotEmpty(passphrase)) {
// 设置带口令的密钥
jsch.addIdentity(privateKey, passphrase);
} else {
// 设置不带口令的密钥
jsch.addIdentity(privateKey);
}
}
Session session = createSession(jsch, host, username, port);
// 设置登陆超时时间
session.connect(15000);
logger.info("Session connected to " + host + ".");
try {
// 创建sftp通信通道
channel = (Channel) session.openChannel(SFTP_PROTOCAL);
channel.connect(1000);
logger.info("Channel created to " + host + ".");
sftp = (ChannelSftp) channel;
} catch (JSchException e) {
logger.error("exception when channel create.", e);
}
return sftp;
}

/**
* upload all the files to the server<br/>
* 将本地文件名为 srcFile 的文件上传到目标服务器, 目标文件名为 dest,<br/>
* 若 dest为目录,则目标文件名将与srcFile文件名相同. 采用默认的传输模式: OVERWRITE
*
* @param sftp
* @param srcFile
* 本地文件的绝对路径
* @param dest
* 目标文件的绝对路径
*/
public static void upload(ChannelSftp sftp, String srcFile, String dest) {
try {
File file = new File(srcFile);
if (file.isDirectory()) {
sftp.cd(srcFile);
for (String fileName : file.list()) {
sftp.put(srcFile + SystemUtils.FILE_SEPARATOR + fileName, dest);
}
}
sftp.put(srcFile, dest);
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* upload all the files to the server<br/>
* 将fileList中的本地文件上传到目标服务器, 目标目录路径为 destPath,<br/>
* destPath必须是目录,目标文件名将与源文件名相同. 采用默认的传输模式: OVERWRITE
*
* @param sftp
* @param fileList
* 要上传到目标服务器的文件的绝对路径
* @param destPath
* 目标文件的绝对路径, 一定是目录, 如果目录不存在则自动创建
* @throws SftpException
*/
public static void upload(ChannelSftp sftp, List<String> fileList, String destPath) throws SftpException {
try {
sftp.cd(destPath);
} catch (Exception e) {
sftp.mkdir(destPath);
}
for (String srcFile : fileList) {
upload(sftp, srcFile, destPath);
}
}

/**
* 使用sftp下载文件
*
* @param sftp
* @param srcPath
* sftp服务器上源文件的路径, 必须是目录
* @param saveFile
* 下载后文件的存储路径, 若为目录, 则文件名将与目标服务器上的文件名相同
* @param srcfile
* 目标服务器上的文件, 不能为目录
*/
public static void download(ChannelSftp sftp, String srcPath, String saveFile, String srcfile) {
try {
sftp.cd(srcPath);
File file = new File(saveFile);
if (file.isDirectory()) {
sftp.get(srcfile, new FileOutputStream(file + SystemUtils.FILE_SEPARATOR + srcfile));
} else {
sftp.get(srcfile, new FileOutputStream(file));
}
} catch (Exception e) {
logger.error("download file: {} error", srcPath + SystemUtils.FILE_SEPARATOR + srcfile, e);
}
}

/**
* 使用sftp下载目标服务器上某个目录下指定类型的文件, 得到的文件名与 sftp服务器上的相同
*
* @param sftp
* @param srcPath
* sftp服务器上源目录的路径, 必须是目录
* @param savePath
* 下载后文件存储的目录路径, 一定是目录, 如果不存在则自动创建
* @param fileTypes
* 指定类型的文件, 文件的后缀名组成的字符串数组
*/
public static void download(ChannelSftp sftp, String srcPath, String savePath, String... fileTypes) {
List<String> fileList = new ArrayList<String>();
try {
sftp.cd(srcPath);
createDir(savePath);
if (fileTypes.length == 0) {
// 列出服务器目录下所有的文件列表
fileList = listFiles(sftp, srcPath, "*");
downloadFileList(sftp, srcPath, savePath, fileList);
return;
}
for (String type : fileTypes) {
fileList = listFiles(sftp, srcPath, "*" + type);
parseAndUpdateDB(sftp, srcPath, savePath, fileList);
}
} catch (Exception e) {
logger.error("download all file in path = '" + srcPath + "' and type in " + Arrays.asList(fileTypes)
+ " error", e);
}

}

private static File createDir(String savePath) throws Exception {
File localPath = new File(savePath);
if (!localPath.exists() && !localPath.isFile()) {
if (!localPath.mkdir()) {
throw new Exception(localPath + " directory can not create.");
}
}
return localPath;
}

/**
* sftp下载目标服务器上srcPath目录下所有指定的文件.<br/>
* 若本地存储路径下存在与下载重名的文件,仍继续下载并覆盖该文件.<br/>
*
* @param sftp
* @param savePath
* 文件下载到本地存储的路径,必须是目录
* @param fileList
* 指定的要下载的文件名列表
* @throws SftpException
* @throws FileNotFoundException
*/
public static void downloadFileList(ChannelSftp sftp, String srcPath, String savePath, List<String> fileList)
throws SftpException, FileNotFoundException {
sftp.cd(srcPath);
for (String srcFile : fileList) {
logger.info("srcFile: " + srcFile);
String localPath = savePath + SystemUtils.FILE_SEPARATOR + srcFile;
sftp.get(srcFile, localPath);
}
}

/**
* sftp下载目标服务器上所有指定的文件, 并解析文件的内容.<br/>
* 若本地存储路径下存在与下载重名的文件, 则忽略(不下载)该文件.<br/>
*
* @param sftp
* @param srcPath
* sftp上源文件的目录
* @param savePath
* 文件下载到本地存储的路径,必须是目录
* @param fileList
* 指定的要下载的文件列表
* @throws FileNotFoundException
* @throws SftpException
*/
private static void parseAndUpdateDB(ChannelSftp sftp, String srcPath, String savePath, List<String> fileList)
throws FileNotFoundException, SftpException {
sftp.cd(srcPath);
for (String srcFile : fileList) {
String localPath = savePath + SystemUtils.FILE_SEPARATOR + srcFile;
File localFile = new File(localPath);
// savePath路径下已有文件与下载文件重名, 忽略这个文件
if (localFile.exists() && localFile.isFile()) {
continue;
}

logger.info("start downloading file: [" + srcFile + "], parseAndUpdate to DB");
sftp.get(srcFile, localPath);
//updateDB(localFile);
}
}

/**
* 获取srcPath路径下以regex格式指定的文件列表
*
* @param sftp
* @param srcPath
* sftp服务器上的目录
* @param regex
* 需要匹配的文件名
* @return
* @throws SftpException
*/
@SuppressWarnings("unchecked")
public static List<String> listFiles(ChannelSftp sftp, String srcPath, String regex) throws SftpException {
List<String> fileList = new ArrayList<String>();
sftp.cd(srcPath); // 如果srcPath不是目录则会抛出异常
if ("".equals(regex) || regex == null) {
regex = "*";
}
Vector<LsEntry> sftpFile = sftp.ls(regex);
String fileName = null;
for (LsEntry lsEntry : sftpFile) {
fileName = lsEntry.getFilename();
fileList.add(fileName);
}
return fileList;
}

/**
* 删除文件
*
* @param dirPath
* 要删除文件所在目录
* @param file
* 要删除的文件
* @param sftp
* @throws SftpException
*/
public static void delete(String dirPath, String file, ChannelSftp sftp) throws SftpException {
String now = sftp.pwd();
sftp.cd(dirPath);
sftp.rm(file);
sftp.cd(now);
}

/**
* Disconnect with server
*/
public static void disconnect(ChannelSftp sftp) {
try {
if (sftp != null) {
if (sftp.isConnected()) {
sftp.disconnect();
} else if (sftp.isClosed()) {
logger.info("sftp is closed already");
}
if (null != sftp.getSession()) {
sftp.getSession().disconnect();
}
}
} catch (JSchException e) {
// Ignore
}

}

private static Session createSession(JSch jsch, String host, String username, int port) throws Exception {
Session session = null;
if (port <= 0) {
// 连接服务器,采用默认端口
session = jsch.getSession(username, host);
} else {
// 采用指定的端口连接服务器
session = jsch.getSession(username, host, port);
}
// 如果服务器连接不上,则抛出异常
if (session == null) {
throw new Exception(host + "session is null");
}
// 设置第一次登陆的时候提示,可选值:(ask | yes | no)
session.setConfig("StrictHostKeyChecking", "no");
return session;
}

public static void down(HttpServletRequest request, HttpServletResponse response, String merNo, String downloadDate, String productNo) {
logger.info("进入下载文件开始...商户号:"+ merNo +",下载日期:"+downloadDate +", 产品类型:" +productNo);
MerchantWebSetting setting = SpringContextHolder.getBean(MerchantWebSetting.class);
String host = setting.getCheckFtpIP();// 主机地址
int port = Integer.parseInt(setting.getCheckFtpPort());// 主机端口
String username = setting.getCheckFtpUser();// 服务器用户名
String password = setting.getCheckFtpPwd();// 服务器密码
String filePath = "reconfile" + File.separator + merNo + File.separator + productNo + File.separator + downloadDate;// 文件所在服务器路径
BufferedInputStream bis = null;
ZipOutputStream zipout = null;
PrintWriter out = null;
ChannelSftp sftp = null;
try {
sftp = connect(host, username, password, port);
List<String> list = listFiles(sftp, filePath, null);
if(null == list || list.size() <= 0){
outPrint(response,"该日期无可下载文件");
return;
}
//sftp.cd(filePath);
response.setCharacterEncoding("UTF-8");
response.setContentType("application/x-msdownload;charset=utf-8");
String outputFilename = productNo+"_"+downloadDate+".zip";
response.setHeader("Content-Disposition", "attachment;filename=" + outputFilename);
zipout = new ZipOutputStream(response.getOutputStream());
byte[] buffer = new byte[1024];
for(String filename : list){
if (sftp.get(filename) != null) {
bis = new BufferedInputStream(sftp.get(filename));
}
zipout.putNextEntry(new ZipEntry(filename));
int len;
// 读入需要下载的文件的内容,打包到zip文件
while ((len = bis.read(buffer)) > 0) {
zipout.write(buffer, 0, len);
}
zipout.closeEntry();
logger.info("sftp文件下载成功,下载的文件是:"+filename);
}
logger.info("sftp文件下载完成...下载的zip文件为:"+outputFilename+",商户号:"+ merNo +",下载日期:"+downloadDate +", 产品类型:" +productNo);
} catch (Exception e) {
logger.error("下载文件出现异常", e);
if(e.getMessage().contains("No such file")){
outPrint(response, "该日期无可下载文件");
}
} finally {
disconnect(sftp);
logger.debug("SFTP连接已断开");
try{
if(zipout != null){
zipout.close();
}
if (bis != null) {
bis.close();
}
if (out != null) {
out.close();
}
}catch(Exception e){
logger.error("sftp下载,关闭输出流出现异常");
}
}
}
/**
*
* @Title: processFileName
*
* @Description: ie,chrom,firfox下处理文件名显示乱码
*/
private static String processFileName(HttpServletRequest request, String fileNames) {
String codedfilename = null;
try {
String agent = request.getHeader("USER-AGENT");
if (null != agent && -1 != agent.indexOf("MSIE") || null != agent
&& -1 != agent.indexOf("Trident")) {// ie
String name = java.net.URLEncoder.encode(fileNames, "UTF8");
codedfilename = name;
} else if (null != agent && -1 != agent.indexOf("Mozilla")) {// 火狐,chrome等
codedfilename = new String(fileNames.getBytes("UTF-8"), "iso-8859-1");
}
} catch (Exception e) {
logger.error(e.getMessage());
}
return codedfilename;
}
private static void outPrint(HttpServletResponse response, String msg){
PrintWriter out = null;
try {
out = response.getWriter();
out.println(msg);
} catch (IOException e) {
e.printStackTrace();
}finally{
if(out != null){
out.flush();
out.close();
}
}
}
public static void main(String[] args) throws Exception {
//"ftp02","62C[82dY0u", "101.200.130.76", 22
ChannelSftp sftp = SftpUtil.connect("101.200.130.76", "ftp02", "62C[82dY0u", 22);
download(sftp, "/reconfile/C1200003030303300000002/0004/20160715", "/Users/luojiaoxia/Downloads", new String[]{});
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值