1. 程式人生 > >利用sftp進行上傳、單個下載、批量下載和刪除

利用sftp進行上傳、單個下載、批量下載和刪除

 最近公司讓用SFTP用來和遠端進行互動,學習了;一段時間sftp,現在將程式碼乾貨獻上,希望對大家能夠有所幫助:

1. 在src/com/zkr/sftp(建議建立在src下)下建立sftp.properties檔案:

               sftp.host=127.0.0.1
               sftp.port=22
               sftp.username=zhen
               sftp.password=12345
               sftp.timeout=60000
               sftp.privateKey
               sftp.passphrase

2. 建立SFTPUtils類,完成上傳、下載、刪除功能:

package com.zkr.sftp;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream.GetField;
import java.util.Iterator;
import java.util.Properties;
import java.util.Vector;

import com.enterprisedt.util.debug.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.SftpATTRS;
import com.jcraft.jsch.SftpException;

public class SftpUtils {

    private static final Logger log = Logger.getLogger(SftpUtils.class); // 用來記錄日誌

    Session session = null;

    String privateKey = null;
    String passphrase = null;
    String host = null; // sftp伺服器的IP
    String username = null; // 使用者名稱
    String password = null; // 密碼
    int timeout = 60000; // 超時時間
    int port = 22; // 埠號

    /**
     * 在建構函式中讀取配置檔案
     */
    public SftpUtils() {

        File file = new File("src/com/zkr/sftp/sftp.properties");
        InputStream in = null;

        try {
            in = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            log.error("異常:檔案沒有找到", e);
        }

        Properties prop = new Properties();
        try {
            prop.load(in);
        } catch (IOException e) {
            log.error("異常:載入配置檔案失敗", e);
        }

        // 讀取配置檔案資訊
        host = prop.getProperty("sftp.host");
        port = Integer.parseInt(prop.getProperty("sftp.port"));
        username = prop.getProperty("sftp.username");
        password = prop.getProperty("sftp.password");
        timeout = Integer.parseInt(prop.getProperty("sftp.timeout"));
        privateKey = prop.getProperty("sftp.privateKey");
        passphrase = prop.getProperty("sftp.passphrase");
        log.info("try to connect to " + host + ",username:" + username
                + ",password:" + password + ",port:" + port);
    }

    /**
     * 得到連線
     * 
     * @return
     */
    private ChannelSftp GetConnectSftp() {
        JSch jsch = new JSch();
        ChannelSftp channelSftp = null;
        try {
            if (privateKey != null && !"".equals(privateKey)) {
                // 使用金鑰驗證方式,金鑰可以使有口令的金鑰,也可以是沒有口令的金鑰
                if (passphrase != null && "".equals(passphrase)) {
                    jsch.addIdentity(privateKey, passphrase);
                } else {
                    jsch.addIdentity(privateKey);
                }
            }
            session = jsch.getSession(username, host, port);
            // 設定密碼
            if (password != null && !"".equals(password)) {
                session.setPassword(password);
            }
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");// do not verify host
            // 為session物件設定properties
            session.setConfig(config);
            // 設定超時
            session.setTimeout(timeout);
            //session.setServerAliveInterval(92000);
            session.connect();
            // 引數sftp指明要開啟的連線是sftp連線
            channelSftp = (ChannelSftp) session.openChannel("sftp");
            channelSftp.connect();
            System.out.println("連線成功");
        } catch (JSchException e) {
            // log.error("異常:連線失敗",e);
            System.out.println("連線失敗");
        }
        return channelSftp;

    }

    /**
     * 下載
     * 
     * @param directory
     *            原始檔在伺服器的路徑,不包括檔名
     * @param srcFilename
     *            原始檔名
     * @param dstPath
     *            下載到本地的目標路徑
     */
    public void download(String directory, String srcFilename, String dstPath) {
        ChannelSftp channelSftp = null;
        // 得到連線
        channelSftp = GetConnectSftp();
        try {
            if (channelSftp != null) {
                // 進入伺服器相應路徑
                channelSftp.cd(directory);
                // 進行下載
                channelSftp.get(srcFilename, dstPath);
                log.info("下載成功:" + srcFilename);
            }
        } catch (SftpException e) {
            log.error("異常:下載失敗:" + srcFilename, e);
            e.printStackTrace();
        } finally {
            // 釋放連線
            disconnected(channelSftp);
        }

    }

    /**
     * 下載 為批量下載做準備
     * 
     * @param directory        原始檔在伺服器的路徑,不包括檔名
     * @param srcFilename    原始檔名
     * @param dstPath        下載到本地的目標路徑
     * @param channelSftp
     */
    private void download(String directory, String srcFilename, String dstPath,
            ChannelSftp channelSftp) {
        try {
            if (channelSftp != null) {
                channelSftp.cd(directory);
                channelSftp.get(srcFilename, dstPath);
            }
        } catch (SftpException e) {
            log.error("異常:  下載失敗:" + directory + "/" + srcFilename, e);
            e.printStackTrace();
        }

    }

    /**
     * 批量下載
     * @param pathName    伺服器端目錄
     * @param dstPath    本地目錄
     */
    public void batchDownload(String pathName, String dstPath) {
        ChannelSftp channelSftp = null;
        // 得到連線
        channelSftp = GetConnectSftp();
        //批量下載管理
        batchDownMag(pathName, dstPath, channelSftp);
        //斷開連線
        disconnected(channelSftp);

    }

    /**
     * 上傳
     * 
     * @param directory
     *            上傳目錄,不包括檔名
     * @param srcPath
     *            本地檔案路徑,包括檔名
     * @param dstFilename
     *            在伺服器中對上傳檔案進行命名
     */
    public void upload(String directory, String srcPath, String dstFilename) {
        ChannelSftp channelSftp = null;
        // 獲取連線
        channelSftp = GetConnectSftp();
        if (channelSftp != null) {
            // 若存在directory這個目錄,則進入其中;若不存在,則先在伺服器先建立該目錄並進入
            createDir(directory, channelSftp);
            try {
                channelSftp.put(srcPath, dstFilename);
                log.info("上傳成功:" + directory);
            } catch (SftpException e) {
                log.error("異常:上傳失敗:" + directory, e);
                e.printStackTrace();
            } finally {
                // 釋放連線
                disconnected(channelSftp);
            }
        }
    }

    /**
     * 刪除檔案
     * 
     * @param directory
     *            要刪除檔案所在目錄,不包括檔名
     * @param deleteFilename
     *            要刪除的檔名
     */
    public void delete(String directory, String deleteFilename) {
        ChannelSftp channelSftp = null;
        // 獲取連線
        channelSftp = GetConnectSftp();
        if (channelSftp != null) {
            try {
                // 進入伺服器相應目錄
                channelSftp.cd(directory);
                // 刪除檔案
                channelSftp.rm(deleteFilename);
            } catch (SftpException e) {
                log.error("異常:刪除失敗:" + deleteFilename, e);
                e.printStackTrace();
            } finally {
                // 釋放連線
                disconnected(channelSftp);
            }

        }
    }

    /**
     * 開啟或進入目錄
     * 
     * @param directory
     * @param channelsftp
     * @return
     */
    private boolean openDir(String directory, ChannelSftp channelsftp) {
        try {
            channelsftp.cd(directory);
            return true;
        } catch (SftpException e) {
            log.error("異常: 該目錄不存在:" + directory, e);
            // e.printStackTrace();
            return false;
        }
    }

    /**
     * 批量下載管理
     * 
     * @param pathName
     *            伺服器端地址
     * @param dstPath
     *            本地地址
     * @param channelSftp
     */
    private void batchDownMag(String pathName, String dstPath,
            ChannelSftp channelSftp) {
        // 確保服務端地址是絕對地址
        if (!pathName.startsWith("/")) {
            pathName = "/" + pathName;
        }
        // 目錄標誌符,若為有效地址,則為true,否則為false
        boolean flag = openDir(pathName, channelSftp);
        if (flag) {
            try {
                Vector vv = channelSftp.ls(pathName);
                if (vv == null && vv.size() == 0) {
                    return;
                } else {
                    // 遍歷當前目錄所有檔案及子資料夾
                    for (Object object : vv) {
                        ChannelSftp.LsEntry entry = (ChannelSftp.LsEntry) object;
                        // 得到當前項的名稱(可能是檔名,也可能是資料夾名)
                        String filename = entry.getFilename();
                        // 去除無關項
                        if (".".equals(filename) || "..".equals(filename)) {
                            continue;
                        }
                        if (openDir(pathName + "/" + filename, channelSftp)) {
                            // 能開啟,說明是目錄,接著遍歷
                            String dstPathChild = dstPath + "/" + filename;
                            File file = new File(dstPathChild);
                            //若本地不存在該目錄,則進行建立
                            if (!file.isDirectory()) {
                                file.mkdirs();
                            }
                            //進行遞迴
                            batchDownMag(pathName + "/" + filename,
                                    dstPathChild, channelSftp);
                        } else {
                            
                            download(pathName, filename, dstPath, channelSftp);
                        }
                    }
                }
            } catch (SftpException e) {
                log.error("遍歷目錄失敗:" + pathName, e);
            }
        } else {
            log.info("對應的目錄" + pathName + "不存在!");
        }

    }

    /**
     * 斷開連線
     * 
     * @param channelSftp
     */
    private void disconnected(ChannelSftp channelSftp) {
        if (channelSftp != null) {
            try {
                // 判斷session是否連線
                if (channelSftp.getSession().isConnected()) {
                    // 若連線,則釋放連線
                    channelSftp.getSession().disconnect();
                }
            } catch (JSchException e) {
                log.error("異常:無法獲取session", e);
                e.printStackTrace();
            }
            // 判斷channelSftp是否連線
            if (channelSftp.isConnected()) {
                // 若連線,則釋放連線
                channelSftp.disconnect();
            }
        }
    }

    /**
     * 若存在相應目錄,則進入該目錄中 若不存在相應目錄,則會在伺服器中建立並進入該目錄中
     * 
     * @param directory
     * @param channelSftp
     */
    private void createDir(String directory, ChannelSftp channelSftp) {
        try {
            // 判斷是否存在相應目錄
            if (isDirExist(directory, channelSftp)) {
                // 若存在,則進入並設定為當前目錄
                channelSftp.cd(directory);
                return;
            }
            // 對路徑進行拆分
            String[] pathArray = directory.split("/");
            // 加"/"設定為絕對路徑
            StringBuffer filePath = new StringBuffer("/");
            for (String path : pathArray) {
                // 若directory為絕對路徑,則為true
                if (path.equals("")) {
                    continue;
                }
                filePath.append(path + "/");
                if (isDirExist(filePath.toString(), channelSftp)) {
                    channelSftp.cd(filePath.toString());
                } else {
                    // 建立目錄
                    channelSftp.mkdir(filePath.toString());
                    // 進入並設定為當前路徑
                    channelSftp.cd(filePath.toString());
                }
            }

        } catch (SftpException e) {
            log.error("異常:建立路徑錯誤:" + directory, e);
            e.printStackTrace();
        }
    }

    /**
     * 判斷目錄是否存在
     * 
     * @param directory
     * @param channelSfrp
     * @return
     */
    private boolean isDirExist(String directory, ChannelSftp channelSftp) {
        boolean isDirExistFlag = false;
        try {
            SftpATTRS sftpATTRS = channelSftp.lstat(directory);
            isDirExistFlag = true;
            return sftpATTRS.isDir();
        } catch (SftpException e) {
            if (e.getMessage().toLowerCase().equals("no such file")) {
                isDirExistFlag = false;
            }
            e.printStackTrace();
        }
        return isDirExistFlag;

    }

}

3.寫測試類進行測試

package com.zkr.sftp;

import com.jcraft.jsch.ChannelSftp;

public class Demo {

       @Test
       public void test1() throws Exception {
        SftpUtils sftputils = new SftpUtils();

        String directory = "sdf/史蒂夫";
        String srcPath = "E:/111/花好月不圓/若只如初見.txt";
        String dstFilename = "情深卻只增悲痛.txt";
        String srcFilename = "秋風何時悲畫卷.xlsx";
        String dstPath = "E:/111/zhen";
        String deleteFilename = "[www.java1234.com]redis設計與實現(第二版).pdf";
        
        //將本地中的E:/111/花好月不圓/若只如初見.txt上傳到sftp伺服器中的sdf/史蒂夫的目錄中,並起名為情深卻只增悲痛.txt
        sftputils.upload(directory, srcPath, dstFilename);
        //將sftp伺服器中的sdf/史蒂夫/秋風何時悲畫卷.xlsx下載到本地的E:/111/zhen目錄中
        sftputils.download(directory, srcFilename, dstPath);
        //刪除sftp伺服器中的sdf/史蒂夫/[www.java1234.com]redis設計與實現(第二版).pdf
        sftputils.delete(directory, deleteFilename);
    }

//測試批量下載功能

   @Test
    public void test2(){
        SftpUtils sftpUtils=new SftpUtils();
        String pathName="/sdf/11/史蒂夫";
        String dstPath="E:/33";
        sftpUtils.batchDownload(pathName, dstPath);
        
    }

}