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

org.aoju.bus.extra.ftp.Ftp Maven / Gradle / Ivy

There is a newer version: 8.0.0
Show newest version
/*********************************************************************************
 *                                                                               *
 * The MIT License (MIT)                                                         *
 *                                                                               *
 * Copyright (c) 2015-2021 aoju.org and other contributors.                      *
 *                                                                               *
 * Permission is hereby granted, free of charge, to any person obtaining a copy  *
 * of this software and associated documentation files (the "Software"), to deal *
 * in the Software without restriction, including without limitation the rights  *
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell     *
 * copies of the Software, and to permit persons to whom the Software is         *
 * furnished to do so, subject to the following conditions:                      *
 *                                                                               *
 * The above copyright notice and this permission notice shall be included in    *
 * all copies or substantial portions of the Software.                           *
 *                                                                               *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR    *
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,      *
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE   *
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER        *
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, *
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN     *
 * THE SOFTWARE.                                                                 *
 *                                                                               *
 ********************************************************************************/
package org.aoju.bus.extra.ftp;

import org.aoju.bus.core.lang.Assert;
import org.aoju.bus.core.lang.Filter;
import org.aoju.bus.core.lang.Normal;
import org.aoju.bus.core.lang.Symbol;
import org.aoju.bus.core.lang.exception.InstrumentException;
import org.aoju.bus.core.toolkit.ArrayKit;
import org.aoju.bus.core.toolkit.FileKit;
import org.aoju.bus.core.toolkit.ObjectKit;
import org.aoju.bus.core.toolkit.StringKit;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * FTP客户端封装
 * 此客户端基于Apache-Commons-Net
 *
 * @author Kimi Liu
 * @version 6.2.2
 * @since JDK 1.8+
 */
public class Ftp extends AbstractFtp {

    /**
     * 默认端口
     */
    public static final int DEFAULT_PORT = 21;

    private FTPClient client;
    private FtpMode mode;
    /**
     * 执行完操作是否返回当前目录
     */
    private boolean backToPwd;

    /**
     * 构造,匿名登录
     *
     * @param host 域名或IP
     */
    public Ftp(String host) {
        this(host, DEFAULT_PORT);
    }

    /**
     * 构造,匿名登录
     *
     * @param host 域名或IP
     * @param port 端口
     */
    public Ftp(String host, int port) {
        this(host, port, "anonymous", Normal.EMPTY);
    }

    /**
     * 构造
     *
     * @param host     域名或IP
     * @param port     端口
     * @param user     用户名
     * @param password 密码
     */
    public Ftp(String host, int port, String user, String password) {
        this(host, port, user, password, org.aoju.bus.core.lang.Charset.UTF_8);
    }

    /**
     * 构造
     *
     * @param host     域名或IP
     * @param port     端口
     * @param user     用户名
     * @param password 密码
     * @param charset  编码
     */
    public Ftp(String host, int port, String user, String password, java.nio.charset.Charset charset) {
        this(host, port, user, password, charset, null, null);
    }

    /**
     * 构造
     *
     * @param host               域名或IP
     * @param port               端口
     * @param user               用户名
     * @param password           密码
     * @param charset            编码
     * @param serverLanguageCode 服务器语言 例如:zh
     * @param systemKey          服务器标识 例如:org.apache.commons.net.ftp.FTPClientConfig.SYST_NT
     */
    public Ftp(String host, int port, String user, String password, java.nio.charset.Charset charset, String serverLanguageCode, String systemKey) {
        this(host, port, user, password, charset, serverLanguageCode, systemKey, null);
    }

    /**
     * 构造
     *
     * @param host               域名或IP
     * @param port               端口
     * @param user               用户名
     * @param password           密码
     * @param charset            编码
     * @param serverLanguageCode 服务器语言
     * @param systemKey          系统关键字
     * @param mode               模式
     */
    public Ftp(String host, int port, String user, String password, Charset charset, String serverLanguageCode, String systemKey, FtpMode mode) {
        this(new FtpConfig(host, port, user, password, charset, serverLanguageCode, systemKey), mode);
    }

    /**
     * 构造
     *
     * @param config FTP配置
     * @param mode   模式
     */
    public Ftp(FtpConfig config, FtpMode mode) {
        super(config);
        this.mode = mode;
        this.init();
    }

    /**
     * 初始化连接
     *
     * @return this
     */
    public Ftp init() {
        return this.init(this.ftpConfig, this.mode);
    }

    /**
     * 初始化连接
     *
     * @param host     域名或IP
     * @param port     端口
     * @param user     用户名
     * @param password 密码
     * @return this
     */
    public Ftp init(String host, int port, String user, String password) {
        return this.init(host, port, user, password, null);
    }

    /**
     * 初始化连接
     *
     * @param host     域名或IP
     * @param port     端口
     * @param user     用户名
     * @param password 密码
     * @param mode     模式
     * @return this
     */
    public Ftp init(String host, int port, String user, String password, FtpMode mode) {
        return init(new FtpConfig(host, port, user, password, this.ftpConfig.getCharset(), null, null), mode);
    }

    /**
     * 初始化连接
     *
     * @param config FTP配置
     * @param mode   模式
     * @return this
     */
    public Ftp init(FtpConfig config, FtpMode mode) {
        final FTPClient client = new FTPClient();
        final Charset charset = config.getCharset();
        if (null != charset) {
            client.setControlEncoding(charset.toString());
        }
        client.setConnectTimeout((int) config.getConnectionTimeout());
        final String systemKey = config.getSystemKey();
        if (StringKit.isNotBlank(systemKey)) {
            final FTPClientConfig conf = new FTPClientConfig(systemKey);
            final String serverLanguageCode = config.getServerLanguageCode();
            if (StringKit.isNotBlank(serverLanguageCode)) {
                conf.setServerLanguageCode(config.getServerLanguageCode());
            }
            client.configure(conf);
        }

        try {
            // 连接ftp服务器
            client.connect(config.getHost(), config.getPort());
            client.setSoTimeout((int) config.getSoTimeout());
            // 登录ftp服务器
            client.login(config.getUser(), config.getPassword());
        } catch (IOException e) {
            throw new InstrumentException(e);
        }
        final int replyCode = client.getReplyCode(); // 是否成功登录服务器
        if (false == FTPReply.isPositiveCompletion(replyCode)) {
            try {
                client.disconnect();
            } catch (IOException e) {
                // ignore
            }
            throw new InstrumentException("Login failed for user [{}], reply code is: [{}]", config.getUser(), replyCode);
        }
        this.client = client;
        if (null != mode) {
            setMode(mode);
        }
        return this;
    }

    /**
     * 设置FTP连接模式,可选主动和被动模式
     *
     * @param mode 模式枚举
     * @return this
     */
    public Ftp setMode(FtpMode mode) {
        this.mode = mode;
        switch (mode) {
            case Active:
                this.client.enterLocalActiveMode();
                break;
            case Passive:
                this.client.enterLocalPassiveMode();
                break;
        }
        return this;
    }

    /**
     * 设置执行完操作是否返回当前目录
     *
     * @param backToPwd 执行完操作是否返回当前目录
     * @return this
     */
    public Ftp setBackToPwd(boolean backToPwd) {
        this.backToPwd = backToPwd;
        return this;
    }

    /**
     * 如果连接超时的话,重新进行连接 经测试,当连接超时时,client.isConnected()仍然返回ture,无法判断是否连接超时 因此,通过发送pwd命令的方式,检查连接是否超时
     *
     * @return this
     */
    @Override
    public Ftp reconnectIfTimeout() {
        String pwd = null;
        try {
            pwd = pwd();
        } catch (InstrumentException fex) {
            // ignore
        }

        if (null == pwd) {
            return this.init();
        }
        return this;
    }

    /**
     * 改变目录
     *
     * @param directory 目录
     * @return 是否成功
     */
    @Override
    public synchronized boolean cd(String directory) {
        if (StringKit.isBlank(directory)) {
            return true;
        }

        try {
            return client.changeWorkingDirectory(directory);
        } catch (IOException e) {
            throw new InstrumentException(e);
        }
    }

    /**
     * 远程当前目录
     *
     * @return 远程当前目录
     */
    @Override
    public String pwd() {
        try {
            return client.printWorkingDirectory();
        } catch (IOException e) {
            throw new InstrumentException(e);
        }
    }

    @Override
    public List ls(String path) {
        return ArrayKit.map(lsFiles(path), FTPFile::getName);
    }

    /**
     * 遍历某个目录下所有文件和目录,不会递归遍历
* 此方法自动过滤"."和".."两种目录 * * @param path 目录 * @param filter 过滤器,null表示不过滤,默认去掉"."和".."两种目录 * @return 文件或目录列表 */ public List lsFiles(String path, Filter filter) { final FTPFile[] ftpFiles = lsFiles(path); if (ArrayKit.isEmpty(ftpFiles)) { return new ArrayList<>(); } final List result = new ArrayList<>(ftpFiles.length - 2 <= 0 ? ftpFiles.length : ftpFiles.length - 2); String fileName; for (FTPFile ftpFile : ftpFiles) { fileName = ftpFile.getName(); if (false == StringKit.equals(".", fileName) && false == StringKit.equals("..", fileName)) { if (null == filter || filter.accept(ftpFile)) { result.add(ftpFile); } } } return result; } /** * 遍历某个目录下所有文件和目录,不会递归遍历 * * @param path 目录,如果目录不存在,抛出异常 * @return 文件或目录列表 * @throws InstrumentException 路径不存在 * @throws InstrumentException IO异常 */ public FTPFile[] lsFiles(String path) throws InstrumentException { String pwd = null; if (StringKit.isNotBlank(path)) { pwd = pwd(); if (false == cd(path)) { throw new InstrumentException("Change dir to [{}] error, maybe path not exist!", path); } } FTPFile[] ftpFiles; try { ftpFiles = this.client.listFiles(); } catch (IOException e) { throw new InstrumentException(e); } finally { cd(pwd); } return ftpFiles; } @Override public boolean mkdir(String dir) { try { return this.client.makeDirectory(dir); } catch (IOException e) { throw new InstrumentException(e); } } /** * 判断ftp服务器文件是否存在 * * @param path 文件路径 * @return 是否存在 */ public boolean existFile(String path) { FTPFile[] ftpFileArr; try { ftpFileArr = client.listFiles(path); } catch (IOException e) { throw new InstrumentException(e); } return ArrayKit.isNotEmpty(ftpFileArr); } /** * 获取服务端目录状态。 * * @param path 路径 * @return 状态int,服务端不同,返回不同 */ public int stat(String path) { try { return this.client.stat(path); } catch (IOException e) { throw new InstrumentException(e); } } @Override public boolean delFile(String path) { final String pwd = pwd(); final String fileName = FileKit.getName(path); final String dir = StringKit.removeSuffix(path, fileName); if (false == cd(dir)) { throw new InstrumentException("Change dir to [{}] error, maybe dir not exist!"); } boolean isSuccess; try { isSuccess = client.deleteFile(fileName); } catch (IOException e) { throw new InstrumentException(e); } finally { cd(pwd); } return isSuccess; } @Override public boolean delDir(String dirPath) { FTPFile[] dirs; try { dirs = client.listFiles(dirPath); } catch (IOException e) { throw new InstrumentException(e); } String name; String childPath; for (FTPFile ftpFile : dirs) { name = ftpFile.getName(); childPath = StringKit.format("{}/{}", dirPath, name); if (ftpFile.isDirectory()) { // 上级和本级目录除外 if (false == ObjectKit.equal(name, Symbol.DOT) && false == ObjectKit.equal(name, Symbol.DOUBLE_DOT)) { delDir(childPath); } } else { delFile(childPath); } } // 删除空目录 try { return this.client.removeDirectory(dirPath); } catch (IOException e) { throw new InstrumentException(e); } } /** * 上传文件到指定目录,可选: * *
     * 1. path为null或""上传到当前路径
     * 2. path为相对路径则相对于当前路径的子路径
     * 3. path为绝对路径则上传到此路径
     * 
* * @param destPath 服务端路径,可以为{@code null} 或者相对路径或绝对路径 * @param file 文件 * @return 是否上传成功 */ @Override public boolean upload(String destPath, File file) { Assert.notNull(file, "file to upload is null !"); return upload(destPath, file.getName(), file); } /** * 上传文件到指定目录,可选: * *
     * 1. path为null或""上传到当前路径
     * 2. path为相对路径则相对于当前路径的子路径
     * 3. path为绝对路径则上传到此路径
     * 
* * @param file 文件 * @param path 服务端路径,可以为{@code null} 或者相对路径或绝对路径 * @param fileName 自定义在服务端保存的文件名 * @return 是否上传成功 */ public boolean upload(String path, String fileName, File file) { try (InputStream in = FileKit.getInputStream(file)) { return upload(path, fileName, in); } catch (IOException e) { throw new InstrumentException(e); } } /** * 上传文件到指定目录,可选: * *
     * 1. path为null或""上传到当前路径
     * 2. path为相对路径则相对于当前路径的子路径
     * 3. path为绝对路径则上传到此路径
     * 
* * @param path 服务端路径,可以为{@code null} 或者相对路径或绝对路径 * @param fileName 文件名 * @param fileStream 文件流 * @return 是否上传成功 */ public boolean upload(String path, String fileName, InputStream fileStream) { try { client.setFileType(FTPClient.BINARY_FILE_TYPE); } catch (IOException e) { throw new InstrumentException(e); } String pwd = null; if (this.backToPwd) { pwd = pwd(); } if (StringKit.isNotBlank(path)) { mkDirs(path); if (false == cd(path)) { throw new InstrumentException("Change dir to [{}] error, maybe dir not exist!"); } } try { return client.storeFile(fileName, fileStream); } catch (IOException e) { throw new InstrumentException(e); } finally { if (this.backToPwd) { cd(pwd); } } } /** * 下载文件 * * @param path 文件路径 * @param outFile 输出文件或目录 */ @Override public void download(String path, File outFile) { final String fileName = FileKit.getName(path); final String dir = StringKit.removeSuffix(path, fileName); download(dir, fileName, outFile); } /** * 下载文件 * * @param path 文件路径 * @param fileName 文件名 * @param outFile 输出文件或目录 */ public void download(String path, String fileName, File outFile) { if (outFile.isDirectory()) { outFile = new File(outFile, fileName); } if (false == outFile.exists()) { FileKit.touch(outFile); } try (OutputStream out = FileKit.getOutputStream(outFile)) { download(path, fileName, out); } catch (IOException e) { throw new InstrumentException(e); } } /** * 下载文件到输出流 * * @param path 文件路径 * @param fileName 文件名 * @param out 输出位置 */ public void download(String path, String fileName, OutputStream out) { download(path, fileName, out, null); } /** * 下载文件到输出流 * * @param path 文件路径 * @param fileName 文件名 * @param out 输出位置 * @param charset 字符编码 */ public void download(String path, String fileName, OutputStream out, java.nio.charset.Charset charset) { String pwd = null; if (this.backToPwd) { pwd = pwd(); } if (false == cd(path)) { throw new InstrumentException("Change dir to [{}] error, maybe dir not exist!"); } if (null != charset) { fileName = new String(fileName.getBytes(charset), StandardCharsets.ISO_8859_1); } try { client.setFileType(FTPClient.BINARY_FILE_TYPE); client.retrieveFile(fileName, out); } catch (IOException e) { throw new InstrumentException(e); } finally { if (backToPwd) { cd(pwd); } } } /** * 递归获取远程文件 * * @param sourcePath 服务器目录 * @param desPath 本地目录 */ @Override public void download(String sourcePath, String desPath) { FTPFile[] lsFiles = lsFiles(sourcePath); for (FTPFile ftpFile : lsFiles) { String sourcePathPathFile = sourcePath + Symbol.SLASH + ftpFile.getName(); String destinationPathFile = desPath + Symbol.SLASH + ftpFile.getName(); if (!ftpFile.isDirectory()) { // 本地不存在文件或者ftp上文件有变更则下载 if (!FileKit.exist(destinationPathFile) || (ftpFile.getTimestamp().getTimeInMillis() > FileKit.lastModifiedTime(destinationPathFile).getTime())) { download(sourcePathPathFile, FileKit.file(destinationPathFile)); } } else if (!(Symbol.DOT.equals(ftpFile.getName()) || Symbol.DOUBLE_DOT.equals(ftpFile.getName()))) { FileKit.mkdir(destinationPathFile); download(sourcePathPathFile, destinationPathFile); } } } /** * 获取FTPClient客户端对象 * * @return {@link FTPClient} */ public FTPClient getClient() { return this.client; } @Override public void close() throws IOException { if (null != this.client) { this.client.logout(); if (this.client.isConnected()) { this.client.disconnect(); } this.client = null; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy