欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java連接FTP服務(wù)器并使用ftp連接池進(jìn)行文件操作指南

 更新時間:2024年08月19日 09:55:50   作者:顧十方  
使用FTP最主要的功能是對文件進(jìn)行管理,下面這篇文章主要給大家介紹了關(guān)于Java連接FTP服務(wù)器并使用ftp連接池進(jìn)行文件操作的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言

使用Java連接FTP服務(wù)器進(jìn)行文件相關(guān)操作,并且使用FTP連接池降低資源消耗,提高響應(yīng)速率。

1、導(dǎo)入Pom依賴

         <!-- https://mvnrepository.com/artifact/commons-net/commons-net -->
        <dependency>
            <groupId>commons-net</groupId>
            <artifactId>commons-net</artifactId>
            <version>3.9.0</version>
        </dependency>

2、創(chuàng)建FTP的配置

ftp:
    # 服務(wù)器地址
    host: xx.xxx.xx.xxx
    # 端口號
    port: 21
    # 用戶名
    userName: xxx
    # 密碼
    password: xxxxxxx
    # 工作目錄
    workingDirectory: /ftpTest
    # 編碼
    encoding: utf-8
    #被動模式
    passiveMode: true
    #連接超時時間
    clientTimeout: 30000
    # 線程數(shù)
    threaNum: 1
    # 0=ASCII_FILE_TYPE(ASCII格式),1=EBCDIC_FILE_TYPE,2=LOCAL_FILE_TYPE(二進(jìn)制文件)
    transferFileType: 2
    # 是否重命名
    renameUploaded: true
    # 重新連接時間
    retryTimes: 1200
    # 緩存大小
    bufferSize: 8192

    # 最大數(shù)
    maxTotal: 50
    # 最小空閑
    minldle: 10
    # 最大空閑
    maxldle: 50
    # 最大等待時間
    maxWait: 30000
    # 池對象耗盡之后是否阻塞,maxWait < 0 時一直等待
    blockWhenExhausted: true
    # 取對象時驗(yàn)證
    testOnBorrow: true
    # 回收驗(yàn)證
    testOnReturn: true
    # 創(chuàng)建時驗(yàn)證
    testOnCreate: true
    # 空閑驗(yàn)證
    testWhileldle: false
    # 后進(jìn)先出
    lifo: false

3、創(chuàng)建FTP配置類

import lombok.Getter;
import lombok.Setter;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.apache.commons.net.ftp.FTPClient;

/**
 * Ftp配置類
 */
@Configuration
@ConfigurationProperties(prefix = "ftp")
@Getter
@Setter
public class FtpConfig extends GenericObjectPoolConfig<FTPClient> {

    /**
     * FTP服務(wù)器地址
     */
    private String host;

    /**
     * FTP服務(wù)器端口
     */
    private Integer port;

    /**
     * FTP用戶名
     */
    private String userName;

    /**
     * FTP密碼
     */
    private String password;

    /**
     * FTP服務(wù)器根目錄
     */
    private String workingDirectory;

    /**
     * 傳輸編碼
     */
    String encoding;

    /**
     * 被動模式:在這種模式下,數(shù)據(jù)連接是由客戶程序發(fā)起的
     */
    boolean passiveMode;

    /**
     * 連接超時時間
     */
    int clientTimeout;

    /**
     * 線程數(shù)
     */
    int threaNum;
    /**
     * 0=ASCII_FILE_TYPE(ASCII格式),1=EBCDIC_FILE_TYPE,2=LOCAL_FILE_TYPE(二進(jìn)制文件)
     */
    int transferFileType;

    /**
     * 是否重命名
     */
    boolean renameUploaded;

    /**
     * 重新連接時間
     */
    int retryTimes;

    /**
     * 緩存大小
     */
    int bufferSize;

    /**
     * 最大數(shù)
     */
    int maxTotal;

    /**
     * 最小空閑
     */
    int minldle;

    /**
     * 最大空閑
     */
    int maxldle;

    /**
     * 最大等待時間
     */
    int maxWait;
    /**
     *  池對象耗盡之后是否阻塞,maxWait < 0 時一直等待
     */
    boolean blockWhenExhausted;
    /**
     * 取對象時驗(yàn)證
     */
    boolean testOnBorrow;
    /**
     * 回收驗(yàn)證
     */
    boolean testOnReturn;
    /**
     * 創(chuàng)建時驗(yàn)證
     */
    boolean testOnCreate;
    /**
     * 空閑驗(yàn)證
     */
    boolean testWhileldle;
    /**
     * 后進(jìn)先出
     */
    boolean lifo;
}

4、創(chuàng)建工廠連接對象并注入配置

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * FtpClient 工廠連接對象
 */
@Component
@Slf4j
public class FTPClientFactory implements PooledObjectFactory<FTPClient> {
    /**
     * 注入 ftp 連接配置
     */
    @Autowired
    FtpConfig config;

    /**
     * 創(chuàng)建連接到池中
     *
     * @return
     * @throws Exception
     */
    @Override
    public PooledObject<FTPClient> makeObject() throws Exception {
        FTPClient ftpClient = new FTPClient();
        ftpClient.setConnectTimeout(config.getClientTimeout());
        ftpClient.connect(config.getHost(), config.getPort());
        int reply = ftpClient.getReplyCode();
        if (!FTPReply.isPositiveCompletion(reply)) {
            ftpClient.disconnect();
            return null;
        }
        boolean success;
        if (StringUtils.isBlank(config.getUserName())) {
            success = ftpClient.login("anonymous", "anonymous");
        } else {
            success = ftpClient.login(config.getUserName(), config.getPassword());
        }
        if (!success) {
            return null;
        }
        ftpClient.setFileType(config.getTransferFileType());
        ftpClient.setBufferSize(1024);
        ftpClient.setControlEncoding(config.getEncoding());
        if (config.isPassiveMode()) {
            ftpClient.enterLocalPassiveMode();
        }
        log.debug("創(chuàng)建ftp連接");
        return new DefaultPooledObject<>(ftpClient);
    }

    /**
     * 鏈接狀態(tài)檢查
     *
     * @param pool
     * @return
     */
    @Override
    public boolean validateObject(PooledObject<FTPClient> pool) {
        FTPClient ftpClient = pool.getObject();
        try {
            return ftpClient != null && ftpClient.sendNoOp();
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 銷毀連接,當(dāng)連接池空閑數(shù)量達(dá)到上限時,調(diào)用此方法銷毀連接
     *
     * @param pool
     * @throws Exception
     */
    @Override
    public void destroyObject(PooledObject<FTPClient> pool) throws Exception {
        FTPClient ftpClient = pool.getObject();
        if (ftpClient != null) {
            try {
                ftpClient.disconnect();
                log.debug("銷毀ftp連接");
            } catch (Exception e) {
                log.error("銷毀ftpClient異常,error:", e.getMessage());
            }
        }
    }

    /**
     * 鈍化連接,是連接變?yōu)榭捎脿顟B(tài)
     *
     * @param p
     * @throws Exception
     */
    @Override
    public void passivateObject(PooledObject<FTPClient> p) throws Exception{
        FTPClient ftpClient = p.getObject();
        try {
            ftpClient.changeWorkingDirectory(config.getWorkingDirectory());
            ftpClient.logout();
            if (ftpClient.isConnected()) {
                ftpClient.disconnect();
            }
        } catch (Exception e) {
            throw new RuntimeException("Could not disconnect from server.", e);
        }
    }

    /**
     * 初始化連接
     *
     * @param pool
     * @throws Exception
     */
    @Override
    public void activateObject(PooledObject<FTPClient> pool) throws Exception {
        FTPClient ftpClient = pool.getObject();
        ftpClient.connect(config.getHost(),config.getPort());
        ftpClient.login(config.getUserName(), config.getPassword());
        ftpClient.setControlEncoding(config.getEncoding());
        ftpClient.changeWorkingDirectory(config.getWorkingDirectory());
        //設(shè)置上傳文件類型為二進(jìn)制,否則將無法打開文件
        ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
    }

    /**
     * 獲取 FTP 連接配置
     * @return
     */
    public FtpConfig getConfig(){
        return config;
    }
}

5、創(chuàng)建客戶端對象service接口

import com.aicut.monitor.config.FtpConfig;
import org.apache.commons.net.ftp.FTPClient;

/**
 * 獲取 ftp 客戶端對象的接口
 */
public interface FTPPoolService {
    /**
     * 獲取ftpClient
     * @return
     */
    FTPClient borrowObject();

    /**
     * 歸還ftpClient
     * @param ftpClient
     * @return
     */
    void returnObject(FTPClient ftpClient);

    /**
     * 獲取 ftp 配置信息
     * @return
     */
    FtpConfig getFtpPoolConfig();
}

6、創(chuàng)建FTP接口實(shí)現(xiàn)類 

import com.aicut.monitor.config.FTPClientFactory;
import com.aicut.monitor.config.FtpConfig;
import com.aicut.monitor.service.FTPPoolService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Component
@Slf4j
public class FTPPoolServiceImpl implements FTPPoolService {

    /**
     * ftp 連接池生成
     */
    private GenericObjectPool<FTPClient> pool;

    /**
     * ftp 客戶端配置文件
     */
    @Autowired
    private FtpConfig config;

    /**
     * ftp 客戶端工廠
     */
    @Autowired
    private FTPClientFactory factory;

    /**
     * 初始化pool
     */
    @PostConstruct
    private void initPool() {
        this.pool = new GenericObjectPool<FTPClient>(this.factory, this.config);
    }

    /**
     * 獲取ftpClient
     */
    @Override
    public FTPClient borrowObject() {
        if (this.pool != null) {
            try {
                return this.pool.borrowObject();
            } catch (Exception e) {
                log.error("獲取 FTPClient 失敗 ", e);
            }
        }
        return null;
    }

    /**
     * 歸還 ftpClient
     */
    @Override
    public void returnObject(FTPClient ftpClient) {
        if (this.pool != null && ftpClient != null) {
            this.pool.returnObject(ftpClient);
        }
    }

    @Override
    public FtpConfig getFtpPoolConfig() {
        return config;
    }
}

7、FTP工具類

import cn.hutool.core.util.CharsetUtil;
import com.aicut.monitor.enums.DownloadStatus;
import com.aicut.monitor.enums.UploadStatus;
import com.aicut.monitor.enums.uploadImageType;
import com.aicut.monitor.service.FTPPoolService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.archivers.zip.ParallelScatterZipCreator;
import org.apache.commons.compress.archivers.zip.UnixStat;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.apache.commons.compress.parallel.InputStreamSupplier;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.input.NullInputStream;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * FTP工具類
 *
 * @author YJ2023085043
 */
@Component
@Slf4j
public class FtpUtil {

    /**
     * ftp 連接池
     */
    @Autowired
    FTPPoolService ftpPoolService;

    public static final String DIR_SPLIT = "/";

    public static final String HTTP_protocol = "http://";


    /**
     * 上傳單個文件
     *
     * @param uploadPath 上傳路徑
     * @param fileName   文件名
     * @param input      文件輸入流
     * @return 上傳結(jié)果
     */
    public UploadStatus upload(String uploadPath, String fileName, InputStream input) {
        FTPClient ftpClient = ftpPoolService.borrowObject();
        try {
            // 切換到工作目錄
            if (!ftpClient.changeWorkingDirectory(uploadPath)) {
                ftpClient.makeDirectory(uploadPath);
                ftpClient.changeWorkingDirectory(uploadPath);
            }
            // 文件寫入
            boolean storeFile = ftpClient.storeFile(fileName, input);
            if (storeFile) {
                log.info("文件:{}上傳成功", fileName);
                return UploadStatus.UploadNewFileSuccess;
            } else {
                throw new RuntimeException("ftp文件寫入異常");
            }
        } catch (IOException e) {
            log.error("文件:{}上傳失敗", fileName, e);
            return UploadStatus.UploadNewFileFailed;
        } finally {
                IOUtils.closeQuietly(input);
                ftpPoolService.returnObject(ftpClient);
            }
    }

    /**
     * 從FTP服務(wù)器上下載文件,支持?jǐn)帱c(diǎn)續(xù)傳,下載百分比匯報
     *
     * @param ftpPath 遠(yuǎn)程文件路徑
     * @param fileName 遠(yuǎn)程文件名
     * @param local  本地文件完整絕對路徑
     * @return 下載的狀態(tài)
     * @throws IOException
     */
    public DownloadStatus downloadFile(String ftpPath, String fileName, String local) throws IOException {
        FTPClient ftpClient = ftpPoolService.borrowObject();
        // 設(shè)置被動模式,由于Linux安全性考慮,端口沒有全部放開,所有被動模式不能用
        ftpClient.enterLocalPassiveMode();
        // 設(shè)置以二進(jìn)制方式傳輸
        ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
        DownloadStatus result;
        try {
            // 檢查遠(yuǎn)程文件是否存在
            FTPFile[] files = ftpClient.listFiles(ftpPath,file -> file.getName().equals(fileName));
            if (files.length != 1) {
                log.info("遠(yuǎn)程文件不存在");
                return DownloadStatus.RemoteFileNotExist;
            }
            long lRemoteSize = files[0].getSize();
            File f = new File(local+DIR_SPLIT+fileName);
            // 本地存在文件,進(jìn)行斷點(diǎn)下載
            if (f.exists()) {
                long localSize = f.length();
                // 判斷本地文件大小是否大于遠(yuǎn)程文件大小
                if (localSize >= lRemoteSize) {
                    log.info("本地文件大于遠(yuǎn)程文件,下載中止");
                    return DownloadStatus.LocalFileBiggerThanRemoteFile;
                }
                // 進(jìn)行斷點(diǎn)續(xù)傳,并記錄狀態(tài)
                FileOutputStream out = new FileOutputStream(f, true);
                ftpClient.setRestartOffset(localSize);
                InputStream in = ftpClient.retrieveFileStream(ftpPath + DIR_SPLIT + fileName);
                byte[] bytes = new byte[1024];
                long step = lRemoteSize / 100;
                // 文件過小,step可能為0
                step = step == 0 ? 1 : step;
                long process = localSize / step;
                int c;
                while ((c = in.read(bytes)) != -1) {
                    out.write(bytes, 0, c);
                    localSize += c;
                    long nowProcess = localSize / step;
                    if (nowProcess > process) {
                        process = nowProcess;
                        if (process % 10 == 0) {
                            log.info("下載進(jìn)度:" + process);
                        }
                    }
                }
                in.close();
                out.close();
                boolean isDo = ftpClient.completePendingCommand();
                if (isDo) {
                    result = DownloadStatus.DownloadFromBreakSuccess;
                } else {
                    result = DownloadStatus.DownloadFromBreakFailed;
                }
            } else {
                OutputStream out = new FileOutputStream(f);
                InputStream in = ftpClient.retrieveFileStream(ftpPath + DIR_SPLIT + fileName);
                byte[] bytes = new byte[1024];
                long step = lRemoteSize / 100;
                // 文件過小,step可能為0
                step = step == 0 ? 1 : step;
                long process = 0;
                long localSize = 0L;
                int c;
                while ((c = in.read(bytes)) != -1) {
                    out.write(bytes, 0, c);
                    localSize += c;
                    long nowProcess = localSize / step;
                    if (nowProcess > process) {
                        process = nowProcess;
                        if (process % 10 == 0) {
                            log.info("下載進(jìn)度:" + process);
                        }
                    }
                }
                in.close();
                out.close();
                boolean upNewStatus = ftpClient.completePendingCommand();
                if (upNewStatus) {
                    result = DownloadStatus.DownloadNewSuccess;
                } else {
                    result = DownloadStatus.DownloadNewFailed;
                }
            }
        } catch (Exception e) {
            log.error("download error", e);
        } finally {
            ftpPoolService.returnObject(ftpClient);
        }
        return DownloadStatus.DownloadNewFailed;
    }

    /**
     * 下載文件到本地 *
     *
     * @param ftpPath     FTP服務(wù)器文件目錄 *
     * @param ftpFileName 文件名稱 *
     * @param localPath   下載后的文件路徑 *
     * @return
     */
    public boolean download(String ftpPath, String ftpFileName, String localPath) {
        FTPClient ftpClient = ftpPoolService.borrowObject();
        OutputStream outputStream = null;
        try {
            FTPFile[] ftpFiles = ftpClient.listFiles(ftpPath, file -> file.isFile() && file.getName().equals(ftpFileName));
            if (ftpFiles != null && ftpFiles.length > 0) {
                FTPFile ftpFile = ftpFiles[0];
                File localFile = new File(localPath + DIR_SPLIT + ftpFile.getName());
                // 判斷本地路徑目錄是否存在,不存在則創(chuàng)建
                if (!localFile.getParentFile().exists()) {
                    localFile.getParentFile().mkdirs();
                }
                outputStream = Files.newOutputStream(localFile.toPath());
                ftpClient.retrieveFile(ftpFile.getName(), outputStream);

                log.info("fileName:{},size:{}", ftpFile.getName(), ftpFile.getSize());
                log.info("下載文件成功...");
                return true;
            } else {
                log.info("文件不存在,filePathname:{},", ftpPath + DIR_SPLIT + ftpFileName);
            }
        } catch (Exception e) {
            log.error("下載文件失敗...",e);
        } finally {
            IOUtils.closeQuietly(outputStream);
            ftpPoolService.returnObject(ftpClient);
        }
        return false;
    }

    /**
     * 下載文件到瀏覽器 *
     *
     * @param ftpPath     FTP服務(wù)器文件目錄 *
     * @param ftpFileName 文件名稱 *
     * @param response
     * @return
     */
    public void download(HttpServletResponse response, String ftpPath, String ftpFileName)  {
        FTPClient ftpClient = ftpPoolService.borrowObject();
        OutputStream outputStream = null;
        try {
            FTPFile[] ftpFiles = ftpClient.listFiles(ftpPath, file -> file.isFile() && file.getName().equals(ftpFileName));
            response.setContentType("application/octet-stream");
            response.setCharacterEncoding("utf8");
            response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(ftpFileName,"UTF-8") );
            outputStream = response.getOutputStream();
            if (ftpFiles != null && ftpFiles.length > 0) {
                FTPFile ftpFile = ftpFiles[0];
                ftpClient.retrieveFile(ftpPath+DIR_SPLIT+ftpFile.getName(), outputStream);

                log.info("fileName:{},size:{}", ftpFile.getName(), ftpFile.getSize());
                log.info("下載文件成功...");
            } else {
                log.info("文件不存在,filePathname:{},", ftpPath + DIR_SPLIT + ftpFileName);
            }
        } catch (Exception e) {
            log.error("下載文件失敗...",e);
        } finally {
            IOUtils.closeQuietly(outputStream);
            ftpPoolService.returnObject(ftpClient);
        }
    }

    public void ftpZipFileDownload (HttpServletResponse response,String ftpPath) {
        //從FTP上下載文件并打成ZIP包給用戶下載
        ZipOutputStream zipOut = null;
        try {
            //文件名稱
            String zipFileName = "導(dǎo)出數(shù)據(jù).zip";
            response.reset();
            // 設(shè)置導(dǎo)出文件頭
            response.setContentType("application/octet-stream");
            response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(zipFileName,"UTF-8") );
            // 定義Zip輸出流
            zipOut = new ZipOutputStream(response.getOutputStream());
            zipFTPFile(ftpPath,zipOut,"");
        } catch (IOException e) {
            log.error("當(dāng)前:"+ftpPath+"下載FTP文件--->下載文件失?。?+e.getMessage());
        } finally {
            // 關(guān)閉zip文件輸出流
            if (null != zipOut) {
                try {
                    zipOut.closeEntry();
                    zipOut.close();
                } catch (IOException e) {
                    log.error("當(dāng)前:"+ftpPath+"下載FTP文件--->關(guān)閉zip文件輸出流出錯:"+e.getMessage());
                }
            }
        }
    }

    public void zipFTPFile(String ftpPath, ZipOutputStream zipOut,String foldPath){
        FTPClient ftpClient = ftpPoolService.borrowObject();
        try {
            // 切換到指定目錄中,如果切換失敗說明目錄不存在
            if(!ftpClient.changeWorkingDirectory(ftpPath)){
                log.error("切換目錄失敗");
                throw new RuntimeException("切換目錄失敗");
            }
            // 每次數(shù)據(jù)連接之前,ftp client告訴ftp server開通一個端口來傳輸數(shù)據(jù)
            ftpClient.enterLocalPassiveMode();
            // 遍歷路徑下的所有文件
            FTPFile[] fileList = ftpClient.listFiles();
            byte[] byteReader = new byte[1024];
            ByteArrayOutputStream os = null;
            for (FTPFile tempFile : fileList) {
                if (tempFile.isFile()) {
                    os = new ByteArrayOutputStream();
                    // 從FTP上下載downFileName該文件把該文件轉(zhuǎn)化為字節(jié)數(shù)組的輸出流
                    ftpClient.retrieveFile(tempFile.getName(), os);
                    byte[] bytes = os.toByteArray();
                    InputStream ins = new ByteArrayInputStream(bytes);

                    int len;
                    zipOut.putNextEntry(new ZipEntry(foldPath + tempFile.getName()));
                    // 讀入需要下載的文件的內(nèi)容,打包到zip文件
                    while ((len = ins.read(byteReader)) > 0) {
                        zipOut.write(byteReader, 0, len);
                    }
                }else{
                    //如果是文件夾,則遞歸調(diào)用該方法
                    zipOut.putNextEntry(new ZipEntry(tempFile.getName() + DIR_SPLIT));
                    zipFTPFile(ftpPath + DIR_SPLIT + tempFile.getName(), zipOut, tempFile.getName() + DIR_SPLIT);
                }
            }
            zipOut.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            ftpPoolService.returnObject(ftpClient);
        }
    }

    /**
     * 得到某個目錄下的文件名列表
     *
     * @param ftpDirPath FTP上的目標(biāo)文件路徑
     * @return
     * @throws IOException
     */
    public List<String> getFileList(String ftpDirPath) {
        FTPClient ftpClient = ftpPoolService.borrowObject();
        try {
            FTPFile[] ftpFiles = ftpClient.listFiles(ftpDirPath);
            if (ftpFiles != null && ftpFiles.length > 0) {
                return Arrays.stream(ftpFiles).map(FTPFile::getName).collect(Collectors.toList());
            }
            log.error(String.format("路徑有誤,或目錄【%s】為空", ftpDirPath));
        } catch (Exception e) {
            log.error("獲取目錄下文件列表失敗", e);
        } finally {
            ftpPoolService.returnObject(ftpClient);
        }
        return null;
    }

    /**
     * 刪除文件
     *
     * @param ftpPath 服務(wù)器文件存儲路徑
     * @param fileName 文件名
     * @return
     * @throws IOException
     */
    public boolean deleteFile(String ftpPath, String fileName) {
        FTPClient ftpClient = ftpPoolService.borrowObject();
        try {
            // 在 ftp 目錄下獲取文件名與 fileName 匹配的文件信息
            FTPFile[] ftpFiles = ftpClient.listFiles(ftpPath, file -> file.getName().equals(fileName));
            // 刪除文件
            if (ftpFiles != null && ftpFiles.length > 0) {
                boolean del;
                String deleteFilePath = ftpPath + DIR_SPLIT + fileName;
                FTPFile ftpFile = ftpFiles[0];
                if (ftpFile.isDirectory()) {
                    //遞歸刪除該目錄下的所有文件后刪除目錄
                    FTPFile[] files = ftpClient.listFiles(ftpPath + DIR_SPLIT + fileName);
                    for (FTPFile file : files) {
                        if(file.isDirectory()){
                            deleteFile(ftpPath + DIR_SPLIT + fileName,file.getName());
                        }else{
                            del = ftpClient.deleteFile(deleteFilePath + DIR_SPLIT + file.getName());
                            log.info(del ? "文件:{}刪除成功" : "文件:{}刪除失敗", file.getName());
                        }
                    }
                    del = ftpClient.removeDirectory(deleteFilePath);
                } else {
                    del = ftpClient.deleteFile(deleteFilePath);
                }
                log.info(del ? "文件:{}刪除成功" : "文件:{}刪除失敗", fileName);
                return del;
            } else {
                log.warn("文件:{}未找到", fileName);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            ftpPoolService.returnObject(ftpClient);
        }
        return false;
    }

    /**
     * 上傳文件到FTP服務(wù)器,支持?jǐn)帱c(diǎn)續(xù)傳
     * @param uploadPath 遠(yuǎn)程文件存放路徑
     * @param fileName 上傳文件名
     * @param input 文件輸入流
     * @return 上傳結(jié)果
     * @throws IOException
     */
    public UploadStatus uploadFile(String uploadPath, String fileName, InputStream input) {
        FTPClient ftpClient = ftpPoolService.borrowObject();
        UploadStatus result = UploadStatus.UploadNewFileFailed;
        try {
            // 設(shè)置PassiveMode傳輸
            ftpClient.enterLocalPassiveMode();
            // 設(shè)置以二進(jìn)制流的方式傳輸
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            ftpClient.setControlEncoding(CharsetUtil.UTF_8);
            //切換到工作目錄
            if(!ftpClient.changeWorkingDirectory(uploadPath)){
                ftpClient.makeDirectory(uploadPath);
                ftpClient.changeWorkingDirectory(uploadPath);
            }
            // 檢查遠(yuǎn)程是否存在文件
            FTPFile[] files = ftpClient.listFiles(uploadPath,file -> file.getName().equals(fileName));
            if (files.length == 1) {
                long remoteSize = files[0].getSize();
                //根據(jù)文件輸入流獲取文件對象
                File f = getFileFromInputStream(input);
                long localSize = f.length();
                // 文件存在
                if (remoteSize == localSize) {
                    return UploadStatus.FileExits;
                } else if (remoteSize > localSize) {
                    return UploadStatus.RemoteFileBiggerThanLocalFile;
                }
                // 嘗試移動文件內(nèi)讀取指針,實(shí)現(xiàn)斷點(diǎn)續(xù)傳
                result = uploadFile(fileName, f, ftpClient, remoteSize);
                // 如果斷點(diǎn)續(xù)傳沒有成功,則刪除服務(wù)器上文件,重新上傳
                if (result == UploadStatus.UploadFromBreakFailed) {
                    if (!ftpClient.deleteFile(fileName)) {
                        return UploadStatus.DeleteRemoteFaild;
                    }
                    result = uploadFile(fileName, f, ftpClient, 0);
                }
            } else {
                result = uploadFile(fileName, getFileFromInputStream(input), ftpClient, 0);
            }
        } catch (Exception e) {
            log.error("上傳文件失敗", e);
        } finally {
            ftpPoolService.returnObject(ftpClient);
        }
        return result;
    }

    /**
     * 從輸入流中獲取文件對象
     * @param inputStream
     * @return
     */
    public static File getFileFromInputStream(InputStream inputStream) {
        File file = null;
        try {
            // 創(chuàng)建臨時文件
            file = File.createTempFile("temp", null);

            // 將輸入流寫入臨時文件
            byte[] buffer = new byte[1024];
            int bytesRead;
            try (FileOutputStream outputStream = new FileOutputStream(file)) {
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return file;
    }

    /**
     * 遞歸創(chuàng)建遠(yuǎn)程服務(wù)器目錄
     *
     * @param remote    遠(yuǎn)程服務(wù)器文件絕對路徑
     * @param ftpClient FTPClient對象
     * @return 目錄創(chuàng)建是否成功
     * @throws IOException
     */

    public UploadStatus createDirectory(String remote, FTPClient ftpClient) throws IOException {
        UploadStatus status = UploadStatus.CreateDirectorySuccess;
        String directory = remote.substring(0, remote.lastIndexOf("/") + 1);
        if (!directory.equalsIgnoreCase("/") && !ftpClient.changeWorkingDirectory(new String(directory.getBytes(CharsetUtil.UTF_8), CharsetUtil.ISO_8859_1))) {
            // 如果遠(yuǎn)程目錄不存在,則遞歸創(chuàng)建遠(yuǎn)程服務(wù)器目錄
            int start = 0;
            int end = 0;
            if (directory.startsWith("/")) {
                start = 1;
            } else {
                start = 0;
            }
            end = directory.indexOf("/", start);
            while (true) {
                String subDirectory = new String(remote.substring(start, end).getBytes(CharsetUtil.UTF_8), CharsetUtil.ISO_8859_1);
                if (!ftpClient.changeWorkingDirectory(subDirectory)) {
                    if (ftpClient.makeDirectory(subDirectory)) {
                        ftpClient.changeWorkingDirectory(subDirectory);
                    } else {
                        log.info("創(chuàng)建目錄失敗");
                        return UploadStatus.CreateDirectoryFail;
                    }
                }
                start = end + 1;
                end = directory.indexOf("/", start);
                // 檢查所有目錄是否創(chuàng)建完畢
                if (end <= start) {
                    break;
                }
            }
        }
        return status;
    }

    /**
     * 上傳文件到服務(wù)器,新上傳和斷點(diǎn)續(xù)傳
     *
     * @param remoteFileName 遠(yuǎn)程文件名,在上傳之前已經(jīng)將服務(wù)器工作目錄做了改變,一定要注意這里的 remoteFile 已經(jīng)別被編碼 ISO-8859-1
     * @param localFile  本地文件File句柄,絕對路徑
     * @param ftpClient  FTPClient引用
     * @return
     * @throws IOException
     */
    public UploadStatus uploadFile(String remoteFileName, File localFile, FTPClient ftpClient, long remoteSize) {
        if (null == ftpClient) {
            ftpClient = ftpPoolService.borrowObject();
        }
        if (null == ftpClient) {
            return null;
        }
        UploadStatus status = UploadStatus.UploadNewFileFailed;

        try (RandomAccessFile raf = new RandomAccessFile(localFile, "r");
             OutputStream out = ftpClient.appendFileStream(remoteFileName);) {
            // 顯示進(jìn)度的上傳
            log.info("localFile.length():" + localFile.length());
            long step = localFile.length() / 100;
            // 文件過小,step可能為0
            step = step == 0 ? 1 : step;
            long process = 0;
            long localreadbytes = 0L;

            // 斷點(diǎn)續(xù)傳
            if (remoteSize > 0) {
                ftpClient.setRestartOffset(remoteSize);
                process = remoteSize / step;
                raf.seek(remoteSize);
                localreadbytes = remoteSize;
            }
            byte[] bytes = new byte[1024];
            int c;
            while ((c = raf.read(bytes)) != -1) {
                out.write(bytes, 0, c);
                localreadbytes += c;
                if (localreadbytes / step != process) {
                    process = localreadbytes / step;
                    if (process % 10 == 0) {
                        log.info("上傳進(jìn)度:" + process);
                    }
                }
            }
            out.flush();
            raf.close();
            out.close();
            // FTPUtil的upload方法在執(zhí)行ftpClient.completePendingCommand()之前應(yīng)該先關(guān)閉OutputStream,否則主線程會在這里卡死執(zhí)行不下去。
            // 原因是completePendingCommand()會一直在等FTP Server返回226 Transfer complete,但是FTP Server只有在接受到OutputStream執(zhí)行close方法時,才會返回。
            boolean result = ftpClient.completePendingCommand();
            if (remoteSize > 0) {
                status = result ? UploadStatus.UploadFromBreakSuccess : UploadStatus.UploadFromBreakFailed;
            } else {
                status = result ? UploadStatus.UploadNewFileSuccess : UploadStatus.UploadNewFileFailed;
            }
        } catch (Exception e) {
            log.error("uploadFile error ", e);
        }
        return status;
    }

    /**
     * 獲取FTP某一特定目錄下的文件數(shù)量
     *
     * @param ftpDirPath FTP上的目標(biāo)文件路徑
     */
    public Integer getFileNum(String ftpDirPath) {
        FTPClient ftpClient = ftpPoolService.borrowObject();
        try {
            FTPFile[] ftpFiles = ftpClient.listFiles(ftpDirPath);
            if (ftpFiles != null && ftpFiles.length > 0) {
                return Arrays.stream(ftpFiles).map(FTPFile::getName).collect(Collectors.toList()).size();
            }
            log.error(String.format("路徑有誤,或目錄【%s】為空", ftpDirPath));
        } catch (IOException e) {
            log.error("文件獲取異常:", e);
        } finally {
            ftpPoolService.returnObject(ftpClient);
        }
        return null;
    }

    /**
     * 獲取文件夾下文件數(shù)量
     * @param ftpPath
     * @return
     */
    public Map<String,String> getDirFileNum(String ftpPath) {
        FTPClient ftpClient = ftpPoolService.borrowObject();
        try {
            Integer sum  = 0;
            Map<String,String> map = new HashMap<>();
            FTPFile[] ftpFiles = ftpClient.listFiles(ftpPath);
            if (ftpFiles != null && ftpFiles.length > 0) {
                for (FTPFile file : ftpFiles) {
                    if (file.isDirectory()) {
                        sum += getFileNum(ftpPath + DIR_SPLIT + file.getName());
                        map.put(file.getName(), String.valueOf(getFileNum(ftpPath + DIR_SPLIT + file.getName())));
                    }
                }
            }else {
                log.error(String.format("路徑有誤,或目錄【%s】為空", ftpPath));
            }
            map.put("sum", String.valueOf(sum));
            return map;
        } catch (IOException e) {
            log.error("文件獲取異常:", e);
        } finally {
            ftpPoolService.returnObject(ftpClient);
        }
        return null;
    }


    /**
     * 下載指定文件夾到本地
     * @param ftpPath FTP服務(wù)器文件目錄
     * @param localPath 下載后的文件路徑
     * @param dirName 文件夾名稱
     * @return
     */
    public void downloadDir(String ftpPath, String localPath, String dirName){
        FTPClient ftpClient = ftpPoolService.borrowObject();
        OutputStream outputStream = null;
        try {
            //判斷是否存在該文件夾
            FTPFile[] ftpFiles = ftpClient.listFiles(ftpPath, file -> file.getName().equals(dirName));
            if (ftpFiles != null && ftpFiles.length > 0) {
                if(ftpFiles[0].isDirectory()) {
                    // 判斷本地路徑目錄是否存在,不存在則創(chuàng)建
                    File localFile = new File(localPath + DIR_SPLIT + dirName);
                    if (!localFile.exists()) {
                        localFile.mkdirs();
                    }
                    for (FTPFile file : ftpClient.listFiles(ftpPath + DIR_SPLIT + dirName)) {
                        if (file.isDirectory()) {
                            downloadDir(ftpPath + DIR_SPLIT + dirName, localPath + dirName + DIR_SPLIT, file.getName());
                        } else {
                            outputStream = Files.newOutputStream(new File(localPath + DIR_SPLIT + dirName + DIR_SPLIT + file.getName()).toPath());
                            ftpClient.retrieveFile(ftpPath + DIR_SPLIT + dirName + DIR_SPLIT + file.getName(), outputStream);
                            log.info("fileName:{},size:{}", file.getName(), file.getSize());
                            outputStream.close();
                        }
                    }
                }
            }
        }catch (Exception e){
            log.error("下載文件夾失敗,filePathname:{},", ftpPath + DIR_SPLIT + dirName, e);
        }finally {
            IOUtils.closeQuietly(outputStream);
            ftpPoolService.returnObject(ftpClient);
        }
    }

        /**
     * 從本地上傳文件夾
     * @param uploadPath ftp服務(wù)器地址
     * @param localPath 本地文件夾地址
     * @param dirName  文件夾名稱
     * @return
     */
    public boolean uploadDir(String uploadPath, String localPath, String dirName){
        FTPClient ftpClient = ftpPoolService.borrowObject();
        try{
            // 切換到工作目錄
            if (!ftpClient.changeWorkingDirectory(uploadPath)) {
                ftpClient.makeDirectory(uploadPath);
                ftpClient.changeWorkingDirectory(uploadPath);
            }
            //創(chuàng)建文件夾
            ftpClient.makeDirectory(uploadPath + DIR_SPLIT + dirName);
            File src = new File(localPath);
            //獲取該目錄下的所有文件
            File[] files = src.listFiles();
            FileInputStream input = null;
            for(File file : files) {
                if (file.isDirectory()) {
                    uploadDir(uploadPath + DIR_SPLIT + dirName, file.getAbsolutePath(), file.getName());
                } else {
                    input = new FileInputStream(file);
                    boolean storeFile = ftpClient.storeFile(uploadPath + DIR_SPLIT + dirName + DIR_SPLIT + file.getName(), input);
                    if (storeFile) {
                        log.info("文件:{}上傳成功", file.getName());
                    } else {
                        throw new RuntimeException("ftp文件寫入異常");
                    }
                }
            }
            if(input != null){
                input.close();
            }
        }catch (Exception e){
            log.error("文件夾上傳失敗",e);
        }finally {
            ftpPoolService.returnObject(ftpClient);
        }
        return false;
    }
}

總結(jié) 

到此這篇關(guān)于Java連接FTP服務(wù)器并使用ftp連接池進(jìn)行文件操作指南的文章就介紹到這了,更多相關(guān)Java連接FTP服務(wù)器進(jìn)行文件操作內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java實(shí)現(xiàn)收藏功能

    java實(shí)現(xiàn)收藏功能

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)收藏功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • 淺談JVM內(nèi)存溢出的幾種方式與解決方法

    淺談JVM內(nèi)存溢出的幾種方式與解決方法

    內(nèi)存溢出分為兩大類:OutOfMemoryError和StackOverflowError,以下舉出10個內(nèi)存溢出的情況,并通過實(shí)例代碼的方式講解了是如何出現(xiàn)內(nèi)存溢出的,感興趣的可以了解一下
    2024-01-01
  • SpringBoot、mybatis返回樹結(jié)構(gòu)的數(shù)據(jù)實(shí)現(xiàn)

    SpringBoot、mybatis返回樹結(jié)構(gòu)的數(shù)據(jù)實(shí)現(xiàn)

    本文主要介紹了SpringBoot、mybatis返回樹結(jié)構(gòu)的數(shù)據(jù)實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • Java中的適配器原理解析

    Java中的適配器原理解析

    這篇文章主要介紹了Java中的適配器原理解析,當(dāng)實(shí)現(xiàn)接口時,為了使所用的類中只實(shí)現(xiàn)需要的方法,使代碼更加簡潔,可以定義一個抽象類實(shí)現(xiàn)接口,將所需要的方法定義為 抽象方法,然后讓類繼承此抽象方法即可,需要的朋友可以參考下
    2023-11-11
  • Java如何通過反射將map轉(zhuǎn)換為實(shí)體對象

    Java如何通過反射將map轉(zhuǎn)換為實(shí)體對象

    在Java開發(fā)中,常需要將XML配置數(shù)據(jù)轉(zhuǎn)為Map,并最終映射到實(shí)體對象上,通過單例模式管理XML轉(zhuǎn)換后的Map,并利用Java反射機(jī)制,通過屬性名稱匹配將Map的值賦給實(shí)體對象的對應(yīng)屬性,這種方法忽略了數(shù)據(jù)類型轉(zhuǎn)換,適用于數(shù)據(jù)類型一致的簡單場景,需要類型轉(zhuǎn)換時
    2024-09-09
  • 你應(yīng)該知道的21個Java核心技術(shù)

    你應(yīng)該知道的21個Java核心技術(shù)

    Java的21個核心技術(shù)點(diǎn),你知道嗎?這篇文章主要為大家詳細(xì)介紹了Java核心技術(shù),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • Spring使用@responseBody與序列化詳解

    Spring使用@responseBody與序列化詳解

    這篇文章主要介紹了Spring使用@responseBody與序列化詳解,@responseBody注解的作用是將controller的方法返回的對象通過適當(dāng)?shù)霓D(zhuǎn)換器轉(zhuǎn)換為指定的格式之后,寫入到response對象的body區(qū),通常用來返回JSON數(shù)據(jù)或者是XML數(shù)據(jù),需要的朋友可以參考下
    2023-08-08
  • Spark隨機(jī)森林實(shí)現(xiàn)票房預(yù)測

    Spark隨機(jī)森林實(shí)現(xiàn)票房預(yù)測

    這篇文章主要為大家詳細(xì)介紹了Spark隨機(jī)森林實(shí)現(xiàn)票房預(yù)測,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • RabbitMQ消息確認(rèn)機(jī)制剖析

    RabbitMQ消息確認(rèn)機(jī)制剖析

    這篇文章主要為大家介紹了RabbitMQ消息確認(rèn)機(jī)制剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • ByteArrayOutputStream與InputStream互相轉(zhuǎn)換方式

    ByteArrayOutputStream與InputStream互相轉(zhuǎn)換方式

    這篇文章主要介紹了ByteArrayOutputStream與InputStream互相轉(zhuǎn)換方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12

最新評論