使用SFTP传输文件

参看:https://www.cnblogs.com/longyg/archive/2012/06/25/2561332.html 《JSch - Java实现的SFTP(文件下载详解篇)》

           http://www.cnblogs.com/longyg/archive/2012/06/25/2556576.html 《JSch - Java实现的SFTP(文件上传详解篇)》

           http://www.idcfree.com/article-1428-1.html《Windows Server 下搭建sftp服务器, Freesshd安装及配置》

           http://blog.csdn.net/ya2dan/article/details/19562605《SFTP连接异常 Could not connect to SFTP server.Caused by:com.jcraft.jsch.JSchException:Auth fail》

           https://zhidao.baidu.com/question/509223259.html 《用java实现sftp下载,报2:No Such file》

        SFTP是Secure File Transfer Protocol的缩写,安全文件传送协议。可以为传输文件提供一种安全的加密方法。SFTP 为 SSH的一部分,是一种传输文件到服务器的安全方式。SFTP是使用加密传输认证信息和传输的数据,所以,使用SFTP是非常安全的。但是,由于这种传输方式使用了加密/解密技术,所以传输效率比普通的FTP要低的多,如果您对网络安全性要求更高时,可以使用SFTP代替FTP。(来自百度的解释)

       JSch 是 Java Secure Channel 的缩写。JSch是一个SSH2的纯Java实现。它允许你连接到一个SSH服务器,并且可以使用端口转发,X11转发,文件传输等,当然你也可以继承它的功能到你自己的应用程序。

       要使用JSch, 需要下载它的jar包,请从官网下载它:http://www.jcraft.com/jsch/

一、ChannelSftp类

       ChannelSftp类是JSch实现SFTP核心类,它包含了所有SFTP的方法,如:

put():      文件上传
get():      文件下载
cd():       进入指定目录
ls():       得到指定目录下的文件列表
rename():   重命名指定文件或目录
rm():       删除指定文件
mkdir():    创建目录
rmdir():    删除目录  

等等;

       JSch支持三种文件传输模式:

OVERWRITE:完全覆盖模式,这是JSch的默认文件传输模式,即如果目标文件已经存在,传输的文件将完全覆盖目标文件,产生新的文件。

RESUME : 恢复模式,如果文件已经传输一部分,这时由于网络或其他任何原因导致文件传输中断,如果下一次传输相同的文件,则会从上一次中断的地方续传。

APPEND:追加模式,如果目标文件已存在,传输的文件将在目标文件后追加。


二、实现SFTP操作的工具类

/*****************************************************************************************************
构造方法摘要--------------------------------------------------------------------------------------------
SftpChannel(String host, int port, int timeout, String username, String password)
参数:
host - SFTP服务器IP地址
port - SFTP服务器端口
timeout - 连接超时时间,单位毫秒
username - 用户名
password - 密码

方法摘要-----------------------------------------------------------------------------------------------
boolean  changeDir(String pathName)                                        : 切换工作目录
boolean  changeToHomeDir()                                                 : 切换到根目录
boolean  changeToParentDir()                                               :切换到上一级目录
String   currentDir()                                                      :当前工作目录
boolean  delDir(String dirName)                                            : 删除文件夹
boolean  delFile(String fileName)                                          :删除文件
boolean  downloadFile(String remotePath, String fileName,String localPath) :下载文件
boolean  exist(String name)                                                : 当前目录是否存在文件或文件夹
boolean  exist(String path, String name)                                   :指定目录下,是否存在文件或文件夹
boolean  existDir(String name)                                             :当前目录是否存在文件夹
boolean  existDir(String path, String name)                                : 指定目录下,是否存在文件夹
boolean  existFile(String name)                                            : 当前目录是否存在文件
boolean  existFile(String path, String name)                               : 指定目录下,是否存在文件
boolean  login()                                                           :登陆SFTP服务器
void	 logout()                                                          : 登出
String[] ls()                                                              :当前目录下文件及文件夹名称列表
String[] ls(String pathName)                                               :指定目录下文件及文件夹名称列表
String[] lsDirs()                                                          : 当前目录下文件夹名称列表
String[] lsDirs(String pathName)                                           :指定目录下文件夹名称列表
String[] lsFiles()                                                         :当前目录下文件名称列表
String[] lsFiles(String pathName)                                          : 指定目录下文件名称列表
boolean	 makeDir(String dirName)                                           :创建目录
boolean	 uploadFile(String pathName,String fileName,InputStream input)     :上传文件
boolean	 uploadFile(String pathName, String fileName, String localFile)    :上传文件
*****************************************************************************************************/
package com.myproject.util;

import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Vector;
import org.apache.log4j.Logger;
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;

public class SftpChannel {
	
	private Logger logger = Logger.getLogger(SftpChannel.class);

	private Session session = null;
	private ChannelSftp channel = null;

	private String host; // SFTP服务器IP地址
	private int port; // SFTP服务器端口 
	private int timeout; // 连接超时时间,单位毫秒
	private String username; // 用户名
	private String password; // 密码 
	
	/**
	 * 构造器
	 * @param host SFTP服务器IP地址
	 * @param port SFTP服务器端口
	 * @param timeout 连接超时时间,单位毫秒 
	 * @param username 用户名
	 * @param password 密码
	 */
	public SftpChannel(String host, int port, int timeout, String username, String password) {
		this.host = host;
		this.port = port;
		this.timeout = timeout;
		this.username = username;
		this.password = password;
	}
	
	/**
	 * 登陆SFTP服务器
	 * @return 是否登录成功
	 */
	public boolean login() {
		try {
			JSch jsch = new JSch();
			session = jsch.getSession(username, host, port);
			if (password != null) {
				session.setPassword(password);
			}
			Properties config = new Properties();
			config.put("StrictHostKeyChecking", "no");
			session.setConfig(config);
			session.setTimeout(timeout);
			session.connect();
			logger.debug("sftp session connected");

			logger.debug("opening channel");
			channel = (ChannelSftp) session.openChannel("sftp");
			channel.connect();

			logger.debug("connected successfully");
			return true;
		} catch (JSchException e) {
			logger.error("sftp login failed", e);
			return false;
		}
	}
	
	/**
	 * 上传文件
	 * @param pathName SFTP服务器目录
	 * @param fileName 服务器上保存的文件名
	 * @param input 输入文件流
	 * @return
	 */
	public boolean uploadFile(String pathName, String fileName, InputStream input) {
		String currentDir = currentDir();
		if (!changeDir(pathName)) {
			return false;
		}

		try {
			channel.put(input, fileName, ChannelSftp.OVERWRITE);
			if (!existFile(fileName)) {
				logger.debug("upload failed");
				return false;
			}
			logger.debug("upload successful");
			return true;
		} catch (SftpException e) {
			logger.error("upload failed", e);
			return false;
		} finally {
			changeDir(currentDir);
		}
	}
	
	/**
	 * 上传文件
	 * @param pathName SFTP服务器目录
	 * @param fileName 服务器上保存的文件名
	 * @param localFile 本地文件
	 * @return
	 */
	public boolean uploadFile(String pathName, String fileName, String localFile) {
		String currentDir = currentDir();
		if (!changeDir(pathName)) {
			return false;
		}

		try {
			channel.put(localFile, fileName, ChannelSftp.OVERWRITE);
			if (!existFile(fileName)) {
				logger.debug("upload failed");
				return false;
			}
			logger.debug("upload successful");
			return true;
		} catch (SftpException e) {
			logger.error("upload failed", e);
			return false;
		} finally {
			changeDir(currentDir);
		}
	}
	
	/**
	 * 下载文件
	 * @param remotePath SFTP服务器目录
	 * @param fileName 服务器上需要下载的文件名
	 * @param localPath 本地保存路径
	 * @return
	 */
	public boolean downloadFile(String remotePath, String fileName, String localPath) {
		String currentDir = currentDir();
		if (!changeDir(remotePath)) {
			return false;
		}

		try {
			String localFilePath = localPath + fileName;
			channel.get(fileName, localFilePath);

			File localFile = new File(localFilePath);
			if (!localFile.exists()) {
				logger.debug("download file failed");
				return false;
			}
			logger.debug("download successful");
			return true;
		} catch (SftpException e) {
			logger.error("download file failed", e);
			return false;
		} finally {
			changeDir(currentDir);
		}
	}
	
	/**
	 * 切换工作目录
	 * @param pathName 路径
	 * @return
	 */
	public boolean changeDir(String pathName) {
		if (pathName == null || pathName.trim().equals("")) {
			logger.debug("invalid pathName");
			return false;
		}

		try {
			channel.cd(pathName.replaceAll("\\\\", "/"));
			logger.debug("directory successfully changed,current dir=" + channel.pwd());
			return true;
		} catch (SftpException e) {
			logger.error("failed to change directory", e);
			return false;
		}
	}
	
	/**
	 * 切换到上一级目录
	 * @return
	 */
	public boolean changeToParentDir() {
		return changeDir("..");
	}
	
	/**
	 * 切换到根目录
	 * @return boolean
	 */
	public boolean changeToHomeDir() {
		String homeDir = null;
		try {
			homeDir = channel.getHome();
		} catch (SftpException e) {
			logger.error("can not get home directory", e);
			return false;
		}
		return changeDir(homeDir);
	}
	
	/**
	 * 创建目录
	 * @param dirName 目录
	 * @return
	 */
	public boolean makeDir(String dirName) {
		try {
			channel.mkdir(dirName);
			logger.debug("directory successfully created,dir=" + dirName);
			return true;
		} catch (SftpException e) {
			logger.error("failed to create directory", e);
			return false;
		}
	}
	
	/**
	 * 删除文件夹
	 * @param dirName
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public boolean delDir(String dirName) {
		if (!changeDir(dirName)) {
			return false;
		}

		Vector<LsEntry> list = null;
		try {
			list = channel.ls(channel.pwd());
		} catch (SftpException e) {
			logger.error("can not list directory", e);
			return false;
		}

		for (LsEntry entry : list) {
			String fileName = entry.getFilename();
			if (!fileName.equals(".") && !fileName.equals("..")) {
				if (entry.getAttrs().isDir()) {
					delDir(fileName);
				} else {
					delFile(fileName);
				}
			}
		}

		if (!changeToParentDir()) {
			return false;
		}

		try {
			channel.rmdir(dirName);
			logger.debug("directory " + dirName + " successfully deleted");
			return true;
		} catch (SftpException e) {
			logger.error("failed to delete directory " + dirName, e);
			return false;
		}
	}
	
	/**
	 * 删除文件
	 * @param fileName 文件名
	 * @return
	 */
	public boolean delFile(String fileName) {
		if (fileName == null || fileName.trim().equals("")) {
			logger.debug("invalid filename");
			return false;
		}

		try {
			channel.rm(fileName);
			logger.debug("file " + fileName + " successfully deleted");
			return true;
		} catch (SftpException e) {
			logger.error("failed to delete file " + fileName, e);
			return false;
		}
	}
	
	/**
	 * 当前目录下文件及文件夹名称列表
	 * @return
	 */
	public String[] ls() {
		return list(Filter.ALL);
	}
	
	/**
	 * 指定目录下文件及文件夹名称列表
	 * @param pathName
	 * @return
	 */
	public String[] ls(String pathName) {
		String currentDir = currentDir();
		if (!changeDir(pathName)) {
			return new String[0];
		}
		;
		String[] result = list(Filter.ALL);
		if (!changeDir(currentDir)) {
			return new String[0];
		}
		return result;
	}

	/**
	 * 当前目录下文件名称列表
	 * @return String[]
	 */
	public String[] lsFiles() {
		return list(Filter.FILE);
	}

	/**
	 * 指定目录下文件名称列表
	 * @return String[]
	 */
	public String[] lsFiles(String pathName) {
		String currentDir = currentDir();
		if (!changeDir(pathName)) {
			return new String[0];
		}
		;
		String[] result = list(Filter.FILE);
		if (!changeDir(currentDir)) {
			return new String[0];
		}
		return result;
	}

	/**
	 * 当前目录下文件夹名称列表
	 * @return String[]
	 */
	public String[] lsDirs() {
		return list(Filter.DIR);
	}

	/**
	 * 指定目录下文件夹名称列表
	 * @return String[]
	 */
	public String[] lsDirs(String pathName) {
		String currentDir = currentDir();
		if (!changeDir(pathName)) {
			return new String[0];
		}
		;
		String[] result = list(Filter.DIR);
		if (!changeDir(currentDir)) {
			return new String[0];
		}
		return result;
	}

	/**
	 * 当前目录是否存在文件或文件夹
	 * @param name       名称
	 * @return boolean
	 */
	public boolean exist(String name) {
		return exist(ls(), name);
	}

	/**
	 * 指定目录下,是否存在文件或文件夹
	 * @param path           目录
	 * @param name      名称
	 * @return boolean
	 */
	public boolean exist(String path, String name) {
		return exist(ls(path), name);
	}

	/**
	 * 当前目录是否存在文件
	 * @param name         文件名
	 * @return boolean
	 */
	public boolean existFile(String name) {
		return exist(lsFiles(), name);
	}

	/**
	 * 指定目录下,是否存在文件
	 * @param path           目录
	 * @param name          文件名
	 * @return boolean
	 */
	public boolean existFile(String path, String name) {
		return exist(lsFiles(path), name);
	}

	/**
	 * 当前目录是否存在文件夹
	 * @param name           文件夹名称
	 * @return boolean
	 */
	public boolean existDir(String name) {
		return exist(lsDirs(), name);
	}

	/**
	 * 指定目录下,是否存在文件夹
	 * @param path           目录
	 * @param name           文家夹名称
	 * @return boolean
	 */
	public boolean existDir(String path, String name) {
		return exist(lsDirs(path), name);
	}

	/**
	 * 当前工作目录 
	 * @return String
	 */
	public String currentDir() {
		try {
			return channel.pwd();
		} catch (SftpException e) {
			logger.error("failed to get current dir", e);
			return homeDir();
		}
	}

	/**
	 * 登出
	 */
	public void logout() {
		if (channel != null) {
			channel.quit();
			channel.disconnect();
		}
		if (session != null) {
			session.disconnect();
		}
		logger.debug("logout successfully");
	}
	
	/** 枚举,用于过滤文件和文件夹 */
	private enum Filter {
		/** 文件及文件夹 */
		ALL,
		/** 文件 */
		FILE,
		/** 文件夹 */
		DIR
	};

	/**
	 * 列出当前目录下的文件及文件夹
	 * @param filter  过滤参数
	 * @return String[]
	 */
	@SuppressWarnings("unchecked")
	private String[] list(Filter filter) {
		Vector<LsEntry> list = null;
		try {
			// ls方法会返回两个特殊的目录,当前目录(.)和父目录(..)
			list = channel.ls(channel.pwd());
		} catch (SftpException e) {
			logger.error("can not list directory", e);
			return new String[0];
		}

		List<String> resultList = new ArrayList<String>();
		for (LsEntry entry : list) {
			if (filter(entry, filter)) {
				resultList.add(entry.getFilename());
			}
		}
		return resultList.toArray(new String[0]);
	}

	/**
	 * 判断是否是否过滤条件
	 * @param entry   LsEntry
	 * @param f       过滤参数
	 * @return boolean
	 */
	private boolean filter(LsEntry entry, Filter f) {
		if (f.equals(Filter.ALL)) {
			return !entry.getFilename().equals(".") && !entry.getFilename().equals("..");
		} else if (f.equals(Filter.FILE)) {
			return !entry.getFilename().equals(".") && !entry.getFilename().equals("..") && !entry.getAttrs().isDir();
		} else if (f.equals(Filter.DIR)) {
			return !entry.getFilename().equals(".") && !entry.getFilename().equals("..") && entry.getAttrs().isDir();
		}
		return false;
	}

	/**
	 * 根目录
	 * @return String
	 */
	private String homeDir() {
		try {
			return channel.getHome();
		} catch (SftpException e) {
			return "/";
		}
	}

	/**
	 * 判断字符串是否存在于数组中
	 * @param strArr     字符串数组
	 * @param str        字符串
	 * @return boolean
	 */
	private boolean exist(String[] strArr, String str) {
		if (strArr == null || strArr.length == 0) {
			return false;
		}
		if (str == null || str.trim().equals("")) {
			return false;
		}
		for (String s : strArr) {
			if (s.equalsIgnoreCase(str)) {
				return true;
			}
		}
		return false;
	}
}





猜你喜欢

转载自blog.csdn.net/xiaoxiaoyusheng2012/article/details/78721142