All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.jiangzeyin.util.net.ftp.FtpUtil Maven / Gradle / Ivy

package cn.jiangzeyin.util.net.ftp;


import cn.jiangzeyin.util.system.util.UtilSystemCache;
import cn.jiangzeyin.util.util.StringUtil;
import cn.jiangzeyin.util.util.file.FileUtil;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.util.Assert;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.LinkedList;

/**
 * ftp 工具
 *
 * @author jiangzeyin
 */
public class FtpUtil {

    private static final String fileEncodingName = "ISO-8859-1";

    /**
     * 创建ftp 连接对象
     *
     * @param server   s
     * @param port     p
     * @param username u
     * @param encoding e
     * @param password p
     * @param mode     mode
     * @return ftp
     * @throws SocketException s
     * @throws IOException     io
     * @author jiangzeyin
     */
    public static FTPClient getFtpClient(String server, int port, String username, String password, String encoding, int mode) throws IOException {
        // FTPClientConfig ftpClientConfig = new
        // FTPClientConfig(FTPClientConfig.SYST_UNIX);
        YokeFtp ftp = new YokeFtp();
        // ftp.configure(config)
        ftp.setDefaultTimeout(40000);
        ftp.setDefaultPort(port);
        ftp.connect(server);
        ftp.setControlEncoding(encoding);
        ftp.login(username, password);
        ftp.setSoTimeout(40000);
        ftp.setConnectTimeout(40000);
        ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
        if (mode == 1)
            ftp.enterLocalPassiveMode();// 被动模式
        else
            ftp.enterLocalActiveMode();// 主动模式
        String FtpRoot = ftp.printWorkingDirectory();
        ftp.changeWorkingDirectory(FtpRoot);
        return ftp;
    }

    /**
     * 获取ftp 连接对象
     *
     * @param ftpInfo ftp
     * @return ftp
     * @throws IOException io
     * @author jiangzeyin
     */
    public static YokeFtp getFtpClient(FtpInfo ftpInfo) throws IOException {
        YokeFtp ftp = new YokeFtp();
        // ftp.setDefaultTimeout(40000);

        ftp.setDefaultPort(ftpInfo.getPort());
        ftp.connect(ftpInfo.getIp());
        ftp.setControlEncoding(ftpInfo.getEncoding());
        // FTP服务器连接回答
        if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
            return null;
        }
        // 登录
        ftp.login(ftpInfo.getUserName(), ftpInfo.getUserPwd());
        ftp.setSoTimeout(ftpInfo.getTimeOut());
        ftp.setConnectTimeout(ftpInfo.getTimeOut());
        if (ftpInfo.getMode() == 1)
            ftp.enterLocalPassiveMode();// 被动模式
        else
            ftp.enterLocalActiveMode();// 主动模式
        ftp.setSchemeId(ftpInfo.getId());
        ftp.setDataTimeout(ftpInfo.getTimeOut());
        ftp.setKeepAlive(true);
        return ftp;
    }

    /**
     * 发送文件到Ftp
     *
     * @param ftpClient  client
     * @param localPath  本地文件目录
     * @param remotePath 远程文件截取目录
     * @param tryCount   tryCount
     * @return boolean
     * @throws IOException io
     * @author XiangZhongBao
     */
    public static boolean togetherUploadFolder(YokeFtp ftpClient, String localPath, String remotePath, int tryCount) throws IOException {
        Assert.notNull(ftpClient);
        LinkedList linkedList = FileUtil.getFolderFiles(localPath);
        Assert.notNull(linkedList, "没有任何文件");
        remotePath = StringUtil.convertNULL(remotePath);
        for (File file : linkedList) {
            if (!file.exists()) {
                UtilSystemCache.getInstance().LOG_INFO().info("错误!文件不存在!" + file.getPath());
                continue;
            }
            String lopath = StringUtil.cleanPath(file.getAbsolutePath());
            String repath = lopath.substring(lopath.indexOf(remotePath));
            String rpath = repath.substring(0, repath.lastIndexOf("/") + 1);
            String rname = repath.substring(repath.lastIndexOf("/") + 1);
            int errorCount = 0;
            boolean isSuccess = false;
            while (errorCount <= tryCount) {
                boolean flag;
                try {
                    flag = uploadFile(ftpClient, file, rpath, rname);
                } catch (SocketTimeoutException e) {
                    UtilSystemCache.getInstance().LOG_ERROR().error("警告:" + lopath + "---读取超时", e);
                    errorCount++;
                    continue;
                } catch (SocketException e) {
                    UtilSystemCache.getInstance().LOG_ERROR().error("错误!链接被重置" + ftpClient.toString(), e);
                    errorCount++;
                    continue;
                } catch (Exception e) {
                    UtilSystemCache.getInstance().LOG_ERROR().error("ftp 发布失败", e);
                    return false;
                }
                if (isSuccess = flag)
                    break;
                else
                    errorCount++;
            }
            if (!isSuccess) {
                UtilSystemCache.getInstance().LOG_INFO().info("sendFile:" + lopath + "错误次数过高,退出发布!");
                return false;
            }
        }
        return true;
    }

    /**
     * ftp 上传文件 文件名为本地文件名
     *
     * @param ftp        ftp
     * @param fileName   name
     * @param remotePath path
     * @return boolean
     * @throws IOException io
     * @author jiangzeyin
     */
    public static boolean FtpUpload(YokeFtp ftp, String fileName, String remotePath) throws IOException {
        return uploadFile(ftp, new File(fileName), remotePath);
    }

    /**
     * ftp 发布单个文件
     *
     * @param ftp        ftp
     * @param fileName   name
     * @param rootPath   path
     * @param remotePath path
     * @return boolean
     * @throws IOException io
     * @author jiangzeyin
     */
    public static boolean FtpUpload(YokeFtp ftp, String fileName, String rootPath, String remotePath) throws IOException {
        File file = new File(fileName);
        String path = FileUtil.getFilePath(file).replace(rootPath, "");
        remotePath = String.format("%s/%s", StringUtil.convertNULL(remotePath), path);
        return uploadFile(ftp, file, remotePath);
    }

    /**
     * ftp 上传文件 文件名为本地文件名
     *
     * @param ftp        ftp
     * @param file       file
     * @param remotePath remotePath
     * @return boolean
     * @throws IOException io
     * @author jiangzeyin
     */
    public static boolean uploadFile(YokeFtp ftp, File file, String remotePath) throws IOException {
        return uploadFile(ftp, file, remotePath, null);
    }

    /**
     * ftp 上传单个文件 文件名为指定 如没有指定则默认为本地文件名
     *
     * @param ftp        ftp
     * @param file       文件对象
     * @param remotePath ftp 文件路径
     * @param remoteName ftp 文件名  默认为本地文件名
     * @return boolean
     * @throws IOException io
     * @author jiangzeyin
     */
    public static boolean uploadFile(YokeFtp ftp, File file, String remotePath, String remoteName) throws IOException {
        Assert.notNull(ftp, "ftp 信息不能为kong");
        Assert.notNull(file, "上传文件不能为空");
        // 文件合法性检查
        if (!file.exists() || file.isDirectory()) {
            throw new IllegalArgumentException("ftp 上传当个文件不存在或者为一个文件夹");
        }
        // 切换路径
        boolean flag = changeWorkingDirectory(ftp, remotePath);
        if (!flag) {
            UtilSystemCache.getInstance().LOG_INFO().info(String.format("ftp切换目录失败,文件:%s", remotePath));
            return false;
        }
        ftp.setBufferSize(4096);// 4096比1024*1024速度要快
        ftp.setControlKeepAliveTimeout(500);
        ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
        ftp.enterLocalPassiveMode();
        InputStream is = new FileInputStream(file);
        // 文件名
        String OnlyFileName;
        if (StringUtil.isEmpty(remoteName)) {
            OnlyFileName = new String(file.getName().getBytes(), fileEncodingName);
        } else {
            OnlyFileName = new String(remoteName.getBytes(), fileEncodingName);
        }
        boolean storeFile = ftp.storeFile(OnlyFileName, is);
        if (!storeFile) {
            UtilSystemCache.getInstance().LOG_INFO().info(String.format("ftp上传失败,文件:%s", storeFile));
        }
        is.close();
        return storeFile;
    }

    /**
     * ftp 上传文件夹
     *
     * @param ftp      ftp
     * @param rootPath rootPath
     * @return boolean
     * @throws IOException io
     * @author jiangzeyin
     */
    public static boolean uploadFolder(YokeFtp ftp, String rootPath) throws IOException {
        File file = new File(rootPath);
        if (!file.isDirectory())
            throw new IllegalArgumentException(rootPath + " 不是一个文件夹");
        return FtpUpload(ftp, rootPath, false);
    }

    /**
     * 上传文件 到指定文件夹下
     *
     * @param ftp         ftp
     * @param rootPath    rootPath
     * @param remotePath  path
     * @param containName 是否包含文件夹名
     * @return boolean
     * @throws IOException io
     * @author jiangzeyin
     */
    public static boolean FtpUpload(YokeFtp ftp, String rootPath, String remotePath, boolean containName) throws IOException {
        File file = new File(rootPath);
        if (!file.exists())
            return false;
        if (file.isDirectory()) {
            return UploadDirectoryPath(ftp, rootPath, file.getPath(), remotePath, containName);
        } else {
            return FtpUploadFile(ftp, file, rootPath, remotePath, containName);
        }
    }

    /**
     * @param ftp         ftp
     * @param rootPath    path
     * @param currPath    path
     * @param remotePath  path
     * @param containName name
     * @return boolean
     * @throws IOException io
     */
    private static boolean UploadDirectoryPath(YokeFtp ftp, String rootPath, String currPath, String remotePath, boolean containName) throws IOException {
        File file = new File(currPath);
        if (!file.exists())
            return false;
        if (!file.isDirectory())
            return false;
        File[] files = file.listFiles();
        if (files == null)
            return false;
        for (File item : files) {
            if (item.isDirectory()) {
                // 继续上传目录
                if (!UploadDirectoryPath(ftp, rootPath, item.getPath(), remotePath, containName))
                    return false;
            } else {
                // 处理单个文件
                boolean flag = FtpUploadFile(ftp, item, rootPath, remotePath, containName);
                if (!flag)
                    return false;
            }
        }
        return true;
    }

    /**
     * ftp 上传文件夹 到根路径
     *
     * @param ftp         ftp
     * @param rootPath    path
     * @param containName name
     * @return boolean
     * @throws IOException io
     * @author jiangzeyin
     */
    public static boolean FtpUpload(YokeFtp ftp, String rootPath, boolean containName) throws IOException {
        return FtpUpload(ftp, rootPath, "/", containName);
    }

    /**
     * 处理上传文件信息
     *
     * @param ftp         ftp
     * @param file        file
     * @param rootPath    本地根路径
     * @param remotePath  上传到远程路径
     *                    默认为根路径
     * @param containName 是否包含文件夹名称
     * @return boolean
     * @throws IOException io
     * @author jiangzeyin
     */
    private static boolean FtpUploadFile(YokeFtp ftp, File file, String rootPath, String remotePath, boolean containName) throws IOException {
        Assert.notNull(file, "上传文件不能为空");
        if (StringUtil.isEmpty(remotePath)) {
            remotePath = "/";
        }
        String newRemotePath = FileUtil.getFilePath(file).replace(rootPath, "");
        newRemotePath = String.format("%s/%s", remotePath, newRemotePath);
        if (containName) {
            String name = new File(rootPath).getName();
            newRemotePath = String.format("%s/%s", name, newRemotePath);
        }
        // 上传文件
        return uploadFile(ftp, file, newRemotePath);
    }

    /**
     * 切换ftp 工作路径
     *
     * @param ftpClient ftp
     * @return boolean
     * @throws IOException io
     * @author jiangzeyin
     */
    private static boolean changeWorkingDirectory(FTPClient ftpClient, String remotePath) throws IOException {
        String directory = FileUtil.clearPath(remotePath);
        // 如果是根路径
        if (directory.equals("/")) {
            ftpClient.changeWorkingDirectory("/");
            return true;
        }
        // 切换到根路径
        if (directory.startsWith("/")) {
            ftpClient.changeWorkingDirectory("/");
        }
        // 切换到对应路径
        if (!ftpClient.changeWorkingDirectory(new String(directory.getBytes(), fileEncodingName))) {
            // 如果远程目录不存在,则递归创建远程服务器目录
            String[] paths = StringUtil.StringToArray(directory, "/");
            for (String string : paths) {
                String subDirectory = new String(string.getBytes(), fileEncodingName);
                if (!ftpClient.changeWorkingDirectory(subDirectory)) {
                    if (ftpClient.makeDirectory(subDirectory)) {
                        if (!ftpClient.changeWorkingDirectory(subDirectory))
                            return false;
                    } else {
                        UtilSystemCache.getInstance().LOG_ERROR().error("ftp 目录创建失败", new RuntimeException(subDirectory));
                        return false;
                    }
                }
            }
        }
        return true;
    }

    /**
     * ftp删除文件及文件夹
     *
     * @param ftp      ftp
     * @param pathName pathName
     * @return boolean
     * @throws IOException io
     */
    public static boolean removeDirectoryALLFile(FTPClient ftp, String pathName) throws IOException {
        FTPFile[] files = ftp.listFiles(pathName);
        if (null != files && files.length > 0) {
            for (FTPFile file : files) {
                if (file.isDirectory()) {
                    removeDirectoryALLFile(ftp, pathName + "/" + file.getName());
                    // 切换到父目录,不然删不掉文件夹
                    ftp.changeWorkingDirectory(pathName.substring(0, pathName.lastIndexOf("/")));
                    ftp.removeDirectory(pathName);
                } else {
                    if (!ftp.deleteFile(pathName + "/" + file.getName())) {
                        return false;
                    }
                }
            }
        }
        // 切换到父目录,不然删不掉文件夹
        ftp.changeWorkingDirectory(pathName.substring(0, pathName.lastIndexOf("/")));
        ftp.removeDirectory(pathName);
        return true;
    }

    /**
     * 删除文件-FTP方式
     *
     * @param ftp  FTPClient对象
     * @param path FTP服务器上传地址
     * @return boolean
     * @throws IOException io
     */
    public static boolean deleteFile(FTPClient ftp, String path) throws IOException {
        return ftp.deleteFile(path);
    }

    /**
     * 关闭连接,使用完连接之后,一定要关闭连接,否则服务器会抛出 Connection reset by peer的错误
     *
     * @param ftpClient ftp
     * @author jiangzeyin
     */
    public static void closeConnection(YokeFtp ftpClient) {
        if (ftpClient == null) {
            return;
        }
        try {
            ftpClient.logout();
            ftpClient.disconnect();
        } catch (IOException e) {
            UtilSystemCache.getInstance().LOG_ERROR().error("关闭ftp 连接错误", e);
        }
    }

    /**
     * 关闭连接,使用完连接之后,一定要关闭连接,否则服务器会抛出 Connection reset by peer的错误
     *
     * @param ftpClients ftp
     * @author jiangzeyin
     */
    public static void closeConnection(YokeFtp[] ftpClients) {
        if (ftpClients == null)
            return;
        for (YokeFtp ftpClient2 : ftpClients) {
            closeConnection(ftpClient2);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy