【VFS】Apache VFS: FTP

使用VFS 连接 FTP

近期项目 需要同时支持 本地/FTP/SFTP/HDFS 文件系统,需要在目标文件系统 读/写 文件,
VFS 虚拟文件系统 屏蔽了不同文件系统底层差异,提供统一接口实现,
因此选用 VFS 实现

VFS 连接FTP

VFS 的maven 坐标

		<!-- vfs -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-vfs2</artifactId>
            <version>2.6.0</version>
        </dependency>
        <!-- FTP -->
        <dependency>
            <groupId>commons-net</groupId>
            <artifactId>commons-net</artifactId>
            <version>3.6</version>
        </dependency>

连接FTP demo

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.vfs2.*;
import org.apache.commons.vfs2.provider.ftp.FtpFileSystemConfigBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

/***
 * demo
 * @author yushangzuiyun2013
 */
public class VfsFtpDemo {
    private static final FileSystemManager instance;
    private static final Logger log = LoggerFactory.getLogger(VfsFtpDemo.class);
    private final String host;
    private final Integer port;
    private final String userName;
    private final String password;

    public VfsFtpDemo(String host, Integer port, String userName, String password) {
        this.host = host;
        this.port = port == null ? 21 : port;
        //需要转义,否则可能账号、密码出现 / %等字符,导致连接失败
        this.userName = encodeSpecialChar(userName);
        this.password = encodeSpecialChar(password);
    }

    public static void main(String[] args) {
        VfsFtpDemo demo = new VfsFtpDemo("192.168.33.32", 21, "ftp-user", "123456");

        try {
            FileObject csvDir = demo.getFile("/source03/csv");
            System.out.println("csvDir: " + csvDir.exists()+", "+csvDir.isFile());

        } catch (FileSystemException e) {
            log.error("获取文件失败!", e);
        }
    }

    /**
     * 获取文件
     * @param path 文件路径,以/开头
     * @return 文件对象
     */
    public FileObject getFile(String path) throws FileSystemException {
        path = path.startsWith("/") ? path : "/" + path;
        String uri = getConnectUrl() + path;
        return instance.resolveFile(uri, getOptions());
    }


    protected String getConnectUrl() {
        StringBuilder sb = new StringBuilder();
        sb.append("ftp://");
        if (StringUtils.isNotEmpty(userName)) {
            sb.append(userName).append(":").append(password).append("@");
        }
        sb.append(host);
        sb.append(":").append(port);
//        sb.append("/");
//        sb.append(connInfo.getPath());
        return sb.toString();
    }
    protected FileSystemOptions getOptions() {
        FtpFileSystemConfigBuilder builder = FtpFileSystemConfigBuilder.getInstance();
        FileSystemOptions options = new FileSystemOptions();
        //解决中文乱码
        builder.setServerLanguageCode(options, "zh");
//        builder.setControlEncoding(options, "UTF-8");
        builder.setAutodetectUtf8(options, true);
        //设置超时时间
        builder.setConnectTimeout(options, 30*1000);
        //设置 被动模式,防止 由于防火墙导致连接不上
        builder.setPassiveMode(options,  true);
        return options;
    }
    /**
     * 对 连接信息中特殊字符进行编码
     */
    protected String encodeSpecialChar(String str){
        if(StringUtils.isEmpty(str)){
            return str;
        }
        try {
            return URLEncoder.encode(str, "UTF-8");
        }catch (UnsupportedEncodingException e){
            return str;
        }
    }

    static {
        try {
            instance = VFS.getManager();
        } catch (FileSystemException e) {
            log.error("获取 VFS管理器 失败!", e);
            throw new RuntimeException(e);
        }
    }

}

常见问题

windows 下能连,Linux上不行,甚至卡死

很可能是 未设置被动模式,默认为主动模式,会分配端口主动连接FTP,但服务器防火墙不允许,
导致一直连接不上,锁一直不释放

密码正确,但连不上FTP

有可能是 密码或用户名带有特殊字符,比如有@等,VFS解析时,错误截断,需要先转义

目录乱码

这要对 VFS设置FTP的文件名编码,代码中 getOptions 即是,可以参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值