1. 程式人生 > >java實現連線vsftpd伺服器,上傳,下載,刪除。

java實現連線vsftpd伺服器,上傳,下載,刪除。

核心程式碼如下:

package com.bh.service;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.IOUtils;
import org.apache.commons.net.PrintCommandListener;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.bh.common.ExceptionUtil;

/**
 * FTP服務工具類
 *
 * @author: Rodge @time: 2017年12月24日 下午23:02:37 @version: V1.0.0
 */
@Component
public class FTPUtilService {

    /** 日誌物件 **/
    private static final Logger log = LoggerFactory.getLogger(FTPUtilService.class);

    /** FTP地址 **/
    @Value(value = "${ftp.ftp_address}")
    private String ftp_address;

    /** FTP埠 **/
    @Value(value = "${ftp.ftp_port}")
    private String ftp_port;

    /** FTP使用者名稱 **/
    @Value(value = "${ftp.ftp_username}")
    private String ftp_username;

    /** FTP密碼 **/
    @Value(value = "${ftp.ftp_password}")
    private String ftp_password;

    /** FTP基礎目錄 **/
    private static final String base_path = "";

    /** 本地字元編碼 **/
    @Value(value = "${ftp.localCharset}")
    private String localCharset;

    /** FTP協議裡面,規定檔名編碼為iso-8859-1 **/
    @Value(value = "${ftp.serverCharset}")
    private String serverCharset;

    /** UTF-8字元編碼 **/
    private static final String CHARSET_UTF8 = "UTF-8";

    /** OPTS UTF8字串常量 **/
    private static final String OPTS_UTF8 = "OPTS UTF8";

    /** 設定緩衝區大小40M **/
    @Value(value = "${ftp.buffer_size}")
    private String buffer_size;

    /** FTPClient物件 **/
    private static FTPClient ftpClient = null;

    /**
     * 本地檔案上傳到FTP伺服器
     *
     * @param ftpPath
     *            FTP伺服器檔案相對路徑,例如:test/123
     * @param multipartFileIOS
     *            上傳時前臺傳過來的multipartFile的檔案輸入流
     * @param fileName
     *            上傳到FTP服務的檔名,例如:666.txt
     * @return boolean 成功返回true,否則返回false
     */
    public boolean uploadLocalFile(String ftpPath, InputStream multipartFileIOS, String fileName) {
        // 登入
        login(ftp_address, Integer.parseInt(ftp_port), ftp_username, ftp_password);
        boolean flag = false;
        if (ftpClient != null) {
            InputStream fis = null;
            try {
                fis = multipartFileIOS;
                ftpClient.setBufferSize(Integer.parseInt(buffer_size));
                // 設定編碼:開啟伺服器對UTF-8的支援,如果伺服器支援就用UTF-8編碼,否則就使用本地編碼(GBK)
                if (FTPReply.isPositiveCompletion(ftpClient.sendCommand(OPTS_UTF8, "ON"))) {
                    localCharset = CHARSET_UTF8;
                }
                ftpClient.setControlEncoding(localCharset);
                ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
                if (!base_path.isEmpty() || !ftpPath.isEmpty()) {
                    String path = changeEncoding(base_path + ftpPath);
                    // 目錄不存在,則遞迴建立
                    if (!ftpClient.changeWorkingDirectory(path)) {
                        this.createDirectorys(path);
                    }
                }
                // 設定被動模式,開通一個埠來傳輸資料
                ftpClient.enterLocalPassiveMode();
                // 上傳檔案
                flag = ftpClient.storeFile(new String(fileName.getBytes(localCharset), serverCharset), fis);
                if (flag) {
                    System.out.println("檔案上傳成功");
                } else {
                    System.out.println("檔案上傳失敗");
                }
            } catch (Exception e) {
                log.error("本地檔案上傳FTP失敗", e);
                e.printStackTrace();
                ExceptionUtil.recordErrorMsg(e);
            } finally {
                IOUtils.closeQuietly(fis);
                closeConnect();
            }
        }
        return flag;
    }

    /**
     * 根據指定目錄獲取該目錄下的檔名稱
     *
     * @param ftpPath
     * @return
     */
    public List<String> getFileNameListByPath(String ftpPath) {
        List<String> fileList = new ArrayList<>();
        // 登入
        login(ftp_address, Integer.parseInt(ftp_port), ftp_username, ftp_password);
        if (ftpClient != null) {
            ftpClient.setBufferSize(Integer.parseInt(buffer_size));
            try {
                if (ftpPath != null && ftpPath != "") {
                    String path = changeEncoding(base_path + ftpPath);
                    // 判斷是否存在該目錄
                    if (!ftpClient.changeWorkingDirectory(path)) {
                        log.error(base_path + ftpPath + "該目錄不存在");
                        return fileList;
                    }
                }
                ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
                ftpClient.enterLocalPassiveMode(); // 設定被動模式,開通一個埠來傳輸資料
                ftpClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out), true));
                String[] fs = ftpClient.listNames();
                if (fs != null && fs.length > 0) {
                    for (String string : fs) {
                        fileList.add(new String(string.getBytes(serverCharset), localCharset));
                    }
                    return fileList;
                }
            } catch (Exception e) {
                e.printStackTrace();
                log.error("下載檔案失敗", e);
                ExceptionUtil.recordErrorMsg(e);
            } finally {
                closeConnect();
            }
        }
        return fileList;
    }

    /**
     * 下載指定檔案到本地
     *
     * @param ftpPath
     *            FTP伺服器檔案相對路徑,例如:test/123
     * @param fileName
     *            要下載的檔名,例如:test.txt
     * @param savePath
     *            儲存檔案到本地的路徑,例如:D:/test
     * @return 成功返回true,否則返回false
     */
    public boolean downloadFile(String ftpPath, String fileName, String savePath) {
        // 登入
        login(ftp_address, Integer.parseInt(ftp_port), ftp_username, ftp_password);
        boolean flag = false;
        if (ftpClient != null) {
            // 設定緩衝區大小
            ftpClient.setBufferSize(Integer.parseInt(buffer_size));
            try {
                if (ftpPath != null && ftpPath != "") {
                    String path = changeEncoding(base_path + ftpPath);
                    // 判斷是否存在該目錄
                    if (!ftpClient.changeWorkingDirectory(path)) {
                        log.error(base_path + ftpPath + "該目錄不存在");
                        return flag;
                    }
                }
                ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
                ftpClient.enterLocalPassiveMode(); // 設定被動模式,開通一個埠來傳輸資料
                ftpClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out), true));
                String[] fs = ftpClient.listNames();
                // 判斷該目錄下是否有檔案
                if (fs == null || fs.length == 0) {
                    log.error(base_path + ftpPath + "該目錄下沒有檔案");
                    return flag;
                }
                for (String ff : fs) {
                    String ftpName = new String(ff.getBytes(serverCharset), localCharset);
                    if (ftpName.equals(fileName)) {
                        File file = new File(savePath + '/' + ftpName);
                        try (OutputStream os = new FileOutputStream(file)) {
                            flag = ftpClient.retrieveFile(ff, os);
                        } catch (Exception e) {
                            log.error(e.getMessage(), e);
                            e.printStackTrace();
                            ExceptionUtil.recordErrorMsg(e);
                        }
                        break;
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                log.error("下載檔案失敗", e);
                e.printStackTrace();
                ExceptionUtil.recordErrorMsg(e);
            } finally {
                closeConnect();
            }
        }
        return flag;
    }

    /**
     * 獲取ftp目錄下所有檔案
     *
     * @param ftpPath
     * @return
     */
    public FTPFile[] getAllFiles(String ftpPath) {
        // 登入
        login(ftp_address, Integer.parseInt(ftp_port), ftp_username, ftp_password);
        if (ftpClient != null) {
            try {
                ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
                String path = changeEncoding(base_path + ftpPath);
                // 判斷是否存在該目錄
                if (!ftpClient.changeWorkingDirectory(path)) {
                    log.error(base_path + ftpPath + "該目錄不存在");
                    return null;
                }
                ftpClient.enterLocalPassiveMode(); // 設定被動模式,開通一個埠來傳輸資料
                FTPFile[] fs = ftpClient.listFiles();
//                FTPFileEntryParser
//                ftpClient.initiateListParsing("NETWARE",path);
//                ftpClient.setParserFactory(new OSSFTPFileEntryParserFactory());
//                FTPFile[] fs = ftpClient.listFiles("./", new FTPFileFilter() {
//                    @Override
//                    public boolean accept(FTPFile file) {
//                        // System.out.println(file.getName());
//                        return true;
//                    }
//                });
                System.out.println("fs.length" + fs.length);
                // 判斷該目錄下是否有檔案
                if (fs == null || fs.length == 0) {
                    log.error(base_path + ftpPath + "該目錄下沒有檔案");
                    return null;
                }
                return fs;
            } catch (IOException e) {
                log.error("獲取檔案失敗", e);
            } finally {
                closeConnect();
            }
        }
        return null;
    }

    /**
     * 根據名稱獲取檔案,以輸入流返回
     *
     * @param ftpPath
     *            FTP伺服器上檔案相對路徑,例如:test/123
     * @param fileName
     *            檔名,例如:test.txt
     * @return InputStream 輸入流物件
     */
    public InputStream getInputStreamByName(String ftpPath, String fileName) {
        // 登入
        login(ftp_address, Integer.parseInt(ftp_port), ftp_username, ftp_password);
        InputStream input = null;
        if (ftpClient != null) {
            // 設定緩衝區大小
            ftpClient.setBufferSize(Integer.parseInt(buffer_size));
            try {
                String path = changeEncoding(base_path + ftpPath);
                // 判斷是否存在該目錄
                if (!ftpClient.changeWorkingDirectory(path)) {
                    log.error(base_path + ftpPath + "該目錄不存在");
                    return input;
                }
                ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
                ftpClient.enterLocalPassiveMode(); // 設定被動模式,開通一個埠來傳輸資料
                ftpClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out), true));
                String[] fs = ftpClient.listNames();
                // 判斷該目錄下是否有檔案
                if (fs == null || fs.length == 0) {
                    log.error(base_path + ftpPath + "該目錄下沒有檔案");
                    return input;
                }
                boolean fileIsExit = false;
                for (String ff : fs) {
                    String ftpName = new String(ff.getBytes(serverCharset), localCharset);
                    if (ftpName.equals(fileName)) {
                        input = ftpClient.retrieveFileStream(ff);
                        byte[] bytes = IOUtils.toByteArray(input);
                        input = new ByteArrayInputStream(bytes);
                        ftpClient.completePendingCommand();
                        fileIsExit = true;
                        break;
                    }
                }
                if (!fileIsExit) {
                    return input;
                }
            } catch (IOException e) {
                log.error("獲取檔案失敗", e);
            } finally {
                closeConnect();
            }
        }
        return input;
    }

    /**
     * 刪除指定檔案
     *
     * @param filePathAndFileName
     *            檔案相對路徑,例如:test/123/test.txt
     * @return 成功返回true,否則返回false
     */
    public boolean deleteFile(String filePathAndFileName) {
        // 登入
        login(ftp_address, Integer.parseInt(ftp_port), ftp_username, ftp_password);
        boolean flag = false;
        if (ftpClient != null) {
            try {
                String path = changeEncoding(base_path + filePathAndFileName);
                ftpClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out), true));
                flag = ftpClient.deleteFile(path);
            } catch (IOException e) {
                log.error("刪除檔案失敗", e);
                e.printStackTrace();
                ExceptionUtil.recordErrorMsg(e);
            } finally {
                closeConnect();
            }
        }
        return flag;
    }

    /**
     * 連線FTP伺服器
     *
     * @param address
     *            地址,如:127.0.0.1
     * @param port
     *            埠,如:21
     * @param username
     *            使用者名稱,如:root
     * @param password
     *            密碼,如:root
     */
    private void login(String address, int port, String username, String password) {
        ftpClient = new FTPClient();
        try {
            ftpClient.connect(address, port);
            ftpClient.login(username, password);
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            int reply = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                closeConnect();
                log.error("FTP伺服器連線失敗");
            }
            System.out.println("FTP登入成功");
        } catch (Exception e) {
            log.error("FTP登入失敗", e);
        }
    }

    /**
     * 關閉FTP連線
     *
     */
    private void closeConnect() {
        if (ftpClient != null && ftpClient.isConnected()) {
            try {
                ftpClient.logout();
                ftpClient.disconnect();
            } catch (IOException e) {
                log.error("關閉FTP連線失敗", e);
            }
        }
    }

    /**
     * FTP伺服器路徑編碼轉換
     *
     * @param ftpPath
     *            FTP伺服器路徑
     * @return String
     */
    private String changeEncoding(String ftpPath) {
        String directory = null;
        try {
            if (FTPReply.isPositiveCompletion(ftpClient.sendCommand(OPTS_UTF8, "ON"))) {
                localCharset = CHARSET_UTF8;
            }
            directory = new String(ftpPath.getBytes(localCharset), serverCharset);
        } catch (Exception e) {
            log.error("路徑編碼轉換失敗", e);
        }
        return directory;
    }

    /**
     * 在伺服器上遞迴建立目錄
     *
     * @param dirPath
     *            上傳目錄路徑
     * @return
     */
    private void createDirectorys(String dirPath) {
        try {
            if (!dirPath.endsWith("/")) {
                dirPath += "/";
            }
            String directory = dirPath.substring(0, dirPath.lastIndexOf("/") + 1);
            ftpClient.makeDirectory("/");
            int start = 0;
            int end = 0;
            if (directory.startsWith("/")) {
                start = 1;
            } else {
                start = 0;
            }
            end = directory.indexOf("/", start);
            while (true) {
                String subDirectory = new String(dirPath.substring(start, end));
                if (!ftpClient.changeWorkingDirectory(subDirectory)) {
                    if (ftpClient.makeDirectory(subDirectory)) {
                        ftpClient.changeWorkingDirectory(subDirectory);
                    } else {
                        log.info("建立目錄失敗");
                        return;
                    }
                }
                start = end + 1;
                end = directory.indexOf("/", start);
                // 檢查所有目錄是否建立完畢
                if (end <= start) {
                    break;
                }
            }
        } catch (Exception e) {
            log.error("上傳目錄建立失敗", e);
        }
    }
}

補充yml配置如下:

 #FTP登入 上傳 下載相關配置
ftp:
  ftp_address: 192.163.20.155  
  ftp_port: 21
  ftp_username: bohua1
  ftp_password: BHsoft13579!
  localCharset: UTF-8
  serverCharset: ISO-8859-1
  buffer_size: 42680320