SFTPUtil

分享 歌唱祖国 ⋅ 于 2019-07-16 14:11:39 ⋅ 197 阅读

package util;

/**

  • @Author: zhicongli
  • @Descirption:
  • @Date: Create in 10:34 2019/7/10
  • @Version: 1.0
  • @Modified By:
    */

import java.io.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Vector;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.apache.log4j.Logger;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import com.jcraft.jsch.ChannelSftp.LsEntry;

/**

  • SFTP(Secure File Transfer Protocol),安全文件传送协议。
    */
    public class SFTPUtil {

    / 日志记录器 */
    private Logger logger = Logger.getLogger(SFTPUtil.class);
    /* Session /
    private Session session = null;
    /
    Channel */
    private ChannelSftp channel = null;
    / SFTP服务器IP地址 */
    private String host;
    /* SFTP服务器端口 /
    private int port;
    /
    连接超时时间,单位毫秒 */
    private int timeout;

    /* 用户名 /
    private String username;
    /* 密码 /
    private String password;

    /**

    • SFTP 安全文件传送协议
    • @param host SFTP服务器IP地址
    • @param port SFTP服务器端口
    • @param timeout 连接超时时间,单位毫秒
    • @param username 用户名
    • @param password 密码
      */
      public SFTPUtil(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 boolean
      */
      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;
      }
      }

    /**

    • 上传文件
    • 使用示例,SFTP服务器上的目录结构如下:/testA/testA_B/
    • 当前目录方法参数:绝对路径/相对路径上传后
    • /uploadFile("testA","upload.txt",new FileInputStream(new File("up.txt")))相对路径/testA/upload.txt
    • /uploadFile("testA/testA_B","upload.txt",new FileInputStream(new File("up.txt")))相对路径/testA/testA_B/upload.txt
    • /uploadFile("/testA/testA_B","upload.txt",new FileInputStream(new File("up.txt")))绝对路径/testA/testA_B/upload.txt
  • @param pathName SFTP服务器目录
  • @param fileName 服务器上保存的文件名
  • @param input 输入文件流
  • @return boolean
    */
    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);
    }
    }

/**

  • 上传文件
  • 使用示例,SFTP服务器上的目录结构如下:/testA/testA_B/
  • 当前目录方法参数:绝对路径/相对路径上传后
  • /uploadFile("testA","upload.txt","up.txt")相对路径/testA/upload.txt
  • /uploadFile("testA/testA_B","upload.txt","up.txt")相对路径/testA/testA_B/upload.txt
  • /uploadFile("/testA/testA_B","upload.txt","up.txt")绝对路径/testA/testA_B/upload.txt
  • @param pathName SFTP服务器目录
  • @param fileName 服务器上保存的文件名
  • @param localFile 本地文件
  • @return boolean
    */
    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);
    }
    }

/**

  • 下载文件
  • 使用示例,SFTP服务器上的目录结构如下:/testA/testA_B/
  • 当前目录方法参数:绝对路径/相对路径下载后
  • /downloadFile("testA","down.txt","D:\\downDir")相对路径D:\\downDir\\down.txt
  • /downloadFile("testA/testA_B","down.txt","D:\\downDir")相对路径D:\\downDir\\down.txt
  • /downloadFile("/testA/testA_B","down.txt","D:\\downDir")绝对路径D:\\downDir\\down.txt
  • @param remotePath SFTP服务器目录
  • @param fileName 服务器上需要下载的文件名
  • @param localPath 本地保存路径
  • @return boolean
    */
    public boolean downloadFile(String remotePath,String fileName,String localPath){

    String currentDir = currentDir();
    if(!changeDir(remotePath)){
    logger.debug("file is not exist");
    return false;
    }

    try {
    String localFilePath = localPath + File.separator + 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);
    }
    }

/**

  • 切换工作目录
  • 使用示例,SFTP服务器上的目录结构如下:/testA/testA_B/
  • 当前目录方法参数(绝对路径/相对路径)切换后的目录
  • /changeDir("testA")相对路径/testA/
  • /changeDir("testA/testA_B")相对路径/testA/testA_B/
  • /changeDir("/testA")绝对路径/testA/
  • /testA/testA_B/changeDir("/testA")绝对路径/testA/
  • @param pathName 路径
  • @return boolean
    */
    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;
    }
    }

/**

  • 切换到上一级目录
  • 使用示例,SFTP服务器上的目录结构如下:/testA/testA_B/
  • 当前目录方法切换后的目录
  • /testA/changeToParentDir()/
  • /testA/testA_B/changeToParentDir()/testA/
  • @return boolean
    */
    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);
    }

/**

  • 创建目录
  • 使用示例,SFTP服务器上的目录结构如下:/testA/testA_B/
  • 当前目录方法参数(绝对路径/相对路径)创建成功后的目录
  • /testA/testA_B/makeDir("testA_B_C")相对路径/testA/testA_B/testA_B_C/
  • /makeDir("/testA/testA_B/testA_B_D")绝对路径/testA/testA_B/testA_B_D/

  • 注意,当中间目录不存在的情况下,不能够使用绝对路径的方式期望创建中间目录及目标目录。
  • 例如makeDir("/testNOEXIST1/testNOEXIST2/testNOEXIST3"),这是错误的。
  • @param dirName 目录
  • @return boolean
    */
    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 boolean
    */
    @SuppressWarnings("unchecked")
    public boolean delDir(String dirName){
    if(!changeDir(dirName)){
    return false;
    }

    Vector 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 boolean
    */
    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 String[]
    */
    public String[] ls(){
    return list(Filter.ALL);
    }

/**

  • 指定目录下文件及文件夹名称列表
  • @return String[]
    */
    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 method ------

/ 枚举,用于过滤文件和文件夹 */
private enum Filter {/* 文件及文件夹 / ALL ,/
文件 */ FILE ,/* 文件夹 / DIR };

/**

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

    List resultList = new ArrayList();
    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;
    }

public InputStream getStream(String remotePath,String fileName){

InputStream inputStream;
String currentDir = currentDir();
if(!changeDir(remotePath)){
    return null;
}

try {

    inputStream = channel.get(fileName);
    logger.debug("download successful");
    return inputStream;
} catch (SftpException e) {
    logger.error("download file failed",e);
    return null;
} finally {
    changeDir(currentDir);
}

}

public void writeFile2Hdfs(String remotePath, String fileName, FileSystem fs, String dstFileName) throws Exception {

String currentDir = currentDir();
Path dstFile = new Path(dstFileName);
FSDataOutputStream outputStream = fs.create(dstFile);
if(!changeDir(remotePath)){
    changeDir(remotePath);
}
InputStream inputStream = channel.get(fileName);
try {
    IOUtils.copyBytes(inputStream, outputStream, 4096, false);
    logger.debug("download successful");

} catch (Exception e) {
    logger.error("download file failed",e);
} finally {
    inputStream.close();
    changeDir(currentDir);
    IOUtils.closeStream(outputStream);
}

}

public void unzipFile2Hdfs(String remotePath, String fileName, FileSystem fs, String dstFileName) throws Exception {
if(!changeDir(remotePath)){
changeDir(remotePath);
}
InputStream inputStream = channel.get(fileName);
ZipInputStream zipIn = new ZipInputStream(inputStream);
ZipEntry entry = zipIn.getNextEntry();

while (entry != null) {
    String filePath = dstFileName + File.separator + entry.getName();
    if (!entry.isDirectory()) {
        // if the entry is a file, extracts it
        extractFile(zipIn, filePath);
    } else {
        // if the entry is a directory, make the directory
        File dir = new File(filePath);
        dir.mkdir();
    }
    zipIn.closeEntry();
    entry = zipIn.getNextEntry();
}

}
private void extractFile(ZipInputStream zipIn, String filePath) throws IOException {
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
byte[] bytesIn = new byte[4096];
int read = 0;
while ((read = zipIn.read(bytesIn)) != -1) {
bos.write(bytesIn, 0, read);
}
bos.close();
}

//------private method ------
}

版权声明:原创作品,允许转载,转载时务必以超链接的形式表明出处和作者信息。否则将追究法律责任。来自海牛部落-歌唱祖国,http://hainiubl.com/topics/36903
成为第一个点赞的人吧 :bowtie:
回复数量: 0
    暂无评论~~
    • 请注意单词拼写,以及中英文排版,参考此页
    • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`, 更多语法请见这里 Markdown 语法
    • 支持表情,可用Emoji的自动补全, 在输入的时候只需要 ":" 就可以自动提示了 :metal: :point_right: 表情列表 :star: :sparkles:
    • 上传图片, 支持拖拽和剪切板黏贴上传, 格式限制 - jpg, png, gif,教程
    • 发布框支持本地存储功能,会在内容变更时保存,「提交」按钮点击时清空
    Ctrl+Enter