当前位置: 首页 > 工具软件 > Commons-VFS > 使用案例 >

【Apache commons】vfs简单使用

长孙承嗣
2023-12-01

vfs 虚拟文件系统

Commons VFS 支持文件系统

1.本地文件

  • [file://]absolute-path

2. Zip, Jar and Tar

3. gzip and bzip2

4. HDFS

5. HTTP and HTTPS

  • http://[username[:password]@]hostname[:port][absolute-path]
  • https://[username[:password]@]hostname[:port][absolute-path]

6. WebDAV

  • webdav://[username[:password]@]hostname[:port][absolute-path]

通过 commons-vfs2-jackrabbit1 和 commons-vfs2-jackrabbit2 模块提供对 WebDAV 服务器上文件的访问。

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-vfs2-jackrabbit1</artifactId>
    <version>2.9.0</version>
</dependency>

7. FTP and FTPS

  • ftp://[user[:pass]@]host[:port][relative-path]
// 默认情况下,路径相对于用户的主目录。可通过以下方式进行更改:
FtpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(options, false);

8. SFTP

  • sftp://[user[:pass]@]hostname[:port][relative-path]

提供对 SFTP 服务器(即 SSH 或 SCP 服务器)上的文件的访问。需要添加如下依赖

<dependency>
    <groupId>com.jcraft</groupId>
    <artifactId>jsch</artifactId>
    <version>0.1.55</version>
</dependency>

9. Temporary Files:提供对临时文件系统的访问,该文件系统在 Commons VFS 关闭时被删除。临时文件系统由本地文件系统支持

10. RAM:在内存中存储所有数据的文件系统(每个文件内容一个字节数组)

  • ram://[path] 示例:ram:///any/path/to/file.txt

11. Resource :实际上不是一个文件系统,它使用 ClassLoader.getResource() 查找资源,并创建一个 VFS url 以供进一步处理

  • res://[path]

12. CIFS

  • smb://[username[:password]@]hostname[:port][absolute-path]

13. MIME:可以读取邮件及其附件,比如归档文件。如果已解析邮件中的某个部分没有名称,则将生成一个伪名称。虚拟名称是:_body_part_X,其中X将被零件号替换。

14. 自定义扩展

整体结构

FileSystemManager

管理一组文件系统。此接口用于按名称从这些文件系统之一中定位获取 org.apache.commons.vfs2.FileObject 。

FileProvider

文件提供者。每个文件提供者负责处理特定 URI 的文件。

FileNameParser

提供将文件名解析为 org.apache.commons.vfs2.FileName 的方法。

FileSystem

一个文件系统,由文件的层次结构组成。

FileObject

代表一个文件,用于访问文件的内容和结构。有两种类型的文件:文件夹,包含其他文件;普通文件,包含数据或内容。一个文件夹可能没有任何内容,普通文件不能包含其他文件。

FilesCache

文件缓存接口。VFS 内置一下几种实现,SoftRefFilesCache(软引用,默认值),WeakRefFilesCache(弱引用),DefaultFilesCache(没有过期和限制),LRUFilesCache(LRU实现,默认容量100个),NullFilesCache(空实现,不做任何缓存)。

FileSelector

该接口用于查找子文件时定义选择规则,使用方式 FileObject.findFiles(FileSelector) 。VFS 内置了 7 种选择器。

public static final FileSelector SELECT_SELF = new FileDepthSelector();
public static final FileSelector SELECT_SELF_AND_CHILDREN = new FileDepthSelector(0, 1);
public static final FileSelector SELECT_CHILDREN = new FileDepthSelector(1);
public static final FileSelector EXCLUDE_SELF = new FileDepthSelector(1, 2147483647);
public static final FileSelector SELECT_FILES;
public static final FileSelector SELECT_FOLDERS;
public static final FileSelector SELECT_ALL;

Apache VFS 提供四个FileSelector实现类:

  • AllFileSelector 顾名思义,将选择所有文件
  • FileDepthSelector (int minDepth, int maxDepth) 选择特定深度的所有文件,以最小深度,最大深度为参数
  • FileFilterSelector 选择所有给定文件对象的子文件。和FileFilter非常象。(那还要这个干什么??),可以接受一个FileFilter作为参数
  • FileTypeSelector (FileType type) 选择特定类型的文件。 Apache VFS的文件类型FileType对象只有四种类型:
    • FILE 文件
    • FILE_OR_FOLDER 文件或目录
    • FOLDER 目录
    • FILE_IMAGINARY 尚不存在的文件

加载流程

VFS 加载文件流程大致如下:FileSystemManager 解析文件名,通过文件名中的协议(如ftp://中的ftp)获取对应 FileProvider 对象,FileProvider 通过 FileNameParser 对象解析文件名获取对应的 FileSystem 对象,通过 FileSystem 对象的 resolveFile 方法获取文件(默认先从缓存中查找,不存在再调用 createFile 方法创建 FileObject 对象,FileObject 就是实体文件的抽象,提供读取和修改等相关能力)

使用apache-commons-vfs

  • 引入依赖
<!-- other -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.31</version>
</dependency>

<!-- vfs -->
<dependency>
    <groupId>commons-net</groupId>
    <artifactId>commons-net</artifactId>
    <version>3.6</version>
</dependency>

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-vfs2</artifactId>
    <version>2.8.0</version>
</dependency>

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.12.0</version>
</dependency>

<!--访问Sftp服务器文件时需要引入-->
<dependency>
    <groupId>com.jcraft</groupId>
    <artifactId>jsch</artifactId>
    <version>0.1.55</version>
</dependency>
<!--访问Http服务器文件时需要引入-->
<dependency>
    <groupId>commons-httpclient</groupId>
    <artifactId>commons-httpclient</artifactId>
    <version>3.1</version>
</dependency>
  • 编写代码
package com.xiaoai.apache_vfs;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.vfs2.*;
import org.apache.commons.vfs2.provider.ftp.FtpFileSystemConfigBuilder;
import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Date;

/**
 * @Author
 * @Date 2021-10-24 14:33
 */
public class MyVfsTest {
    private static final Logger logger = LoggerFactory.getLogger(MyVfsTest.class);
    private static FileSystemManager fsMng = null;

    /**
     * 初始化vfs
     * @return
     * @throws FileSystemException
     */
    public synchronized FileSystemManager vfsInit() throws FileSystemException {
        logger.debug("vfs使用,初始化信息...");
        if (fsMng == null) {
            try {
                FTPSetting();
                SFTPSetting();
                fsMng = VFS.getManager();
            } catch (FileSystemException ex) {
                logger.debug("vfs使用,初始化信息...失败",ex);
                throw new FileSystemException(ex);
            }
        }
        return fsMng;
    }

    private static FileSystemOptions FTPSetting(){
        FtpFileSystemConfigBuilder builder = FtpFileSystemConfigBuilder.getInstance();
        FileSystemOptions options = new FileSystemOptions();
        //解决中文乱码
        builder.setControlEncoding(options, "UTF-8");
        builder.setServerLanguageCode(options, "zh");
        return options;
    }

    private static FileSystemOptions SFTPSetting() throws FileSystemException {
        FileSystemOptions options = new FileSystemOptions();
        SftpFileSystemConfigBuilder sftpBuilder = SftpFileSystemConfigBuilder.getInstance();
        // 设false时,URI要传绝对路径,设true时,URI传相对于远程用户根目录的相对路径
        sftpBuilder.setUserDirIsRoot(options, true);
        sftpBuilder.setStrictHostKeyChecking(options, "no");
//        sftpBuilder.setTimeout(options, 10000);
        return options;
    }

    public static void delete(String path) {
        try {
            FileObject fo = fsMng.resolveFile(path);
            fo.delete();
        } catch (FileSystemException e) {
            e.printStackTrace();
        }
    }

    public static boolean isDirectory(String path) {
        try {
            FileObject fo = fsMng.resolveFile(path);
            return fo.getType().equals(FileType.FOLDER);
        } catch (FileSystemException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 获取输入流
     *
     * @param url
     * @return 文件输入流
     * @throws IOException
     */
    public static InputStream getFileToInputStream(String url) throws IOException{
        try {
            FileObject fo = fsMng.resolveFile(url);
            return fo.getContent().getInputStream();
        } catch (FileSystemException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    public static OutputStream getOutputStream(String path) {
        try {
            FileObject fo = fsMng.resolveFile(path);
            return fo.getContent().getOutputStream();
        } catch (FileSystemException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取字节数组
     *
     * @param url
     * @return 文件字节数组
     * @throws IOException
     */
    public static byte[] getFileToByte(String url) throws IOException{
        InputStream inputStream = getFileToInputStream(url);
        return IOUtils.toByteArray(inputStream);
    }

    /**
     * 文件上传
     * @param uploadURL
     * @param bytes
     * @return
     */
    public static boolean uploadFileToByte(String uploadURL,byte[] bytes){
        OutputStream output  =  null;
        FileObject ftpFile  = null;
        try {
            long byteLength = bytes.length;
            ftpFile = fsMng.resolveFile(uploadURL);
            if(ftpFile != null && ftpFile.exists() == false){
                ftpFile.createFile();
            }
            output = ftpFile.getContent().getOutputStream();
            IOUtils.write(bytes,output);
            if(ftpFile.isFile()){
                long size = ftpFile.getContent().getSize();
                if(byteLength == size){
                    logger.debug("文件上传成功size:{}",size);
                    return true;
                }
            }else{
                logger.debug("创建文件夹成功getURL:{}",ftpFile.getURL());
                return true;
            }
            return false;
        }catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(output != null){
                try {
                    output.close();
                    output.flush();
                    ftpFile.close();
                } catch (Exception var2) {
                   var2.printStackTrace();
                }
            }
        }
        return false;
    }

    public static boolean isFile(String path) {
        try {
            FileObject fo = fsMng.resolveFile(path);
            return fo.getType().equals(FileType.FILE);
        } catch (FileSystemException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 函数描述:根据传入的文件路径创建文件夹(包括各级父文件夹)。如果路径中有文件,会自动去掉文件名。 (文件的判断是
     * 以最后一个"/"之后是否有"."为标识的,)
     *
     * @param path
     * @return 如果创建成功,返回true;否则,返回false;
     */
    public static boolean mkdirs(String path) {
        String realPath = "";
        path = path.replaceAll("\\\\", "/");
        // 如果该路径已"/"结尾,则整个字符串都是路径
        if (path.endsWith("/")) {
            realPath = path;
        } else {
            int fileNamePoint = path.lastIndexOf("/");
            // 获取真正的路径
            if (fileNamePoint >= 0) {
                realPath = path.substring(0, fileNamePoint);
            }
            // 读取文件名
            String fileName = path.substring(fileNamePoint + 1);
            // 如果读取的文件名中没有".",说明整个字符串都是路径
            if (fileName.indexOf(".") < 0) {
                realPath = path;
            }
        }
        try {
            FileObject fo = fsMng.resolveFile(realPath);
            fo.createFolder();
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 函数描述:对文件进行copy
     *
     * @param sourceFilePath 源文件的全部路径+文件名
     * @param targetFilePath 目标文件的全部路径+文件名
     * @param overWrite      如果目标文件存在,是否覆盖。true:覆盖;false:不覆盖(当源文件和目标文件都存在并且不覆盖时,返回true)。
     * @return true:成功;false:失败; (当源文件和目标文件都存在并且不覆盖时,返回true)。
     */
    public static boolean copyFile(String sourceFilePath, String targetFilePath, boolean overWrite) throws IOException {
        if (StringUtils.isBlank(sourceFilePath) || StringUtils.isBlank(targetFilePath)) {
            throw new IOException("源文件或者目标文件为空");
        }
        FileObject from = fsMng.resolveFile(sourceFilePath);
        FileObject to = fsMng.resolveFile(targetFilePath);
        if (to.exists()) {
            if (to.getType() == FileType.FILE) {
                if (overWrite && !to.delete()) {
                    throw new IOException("目标文件[" + targetFilePath + "]被保护,不能被覆盖!");
                } else if (!overWrite) {
                    throw new IOException("目标文件[" + targetFilePath + "]已经存在!");
                }
            }
        }
        to.copyFrom(from, Selectors.SELECT_ALL);
        return true;
    }

    /**
     * Moving a File to Another File ,没有进行磁盘空间大小的判断
     *
     * @param srcFile    源文件 eg: c:\windows\abc.txt
     * @param targetFile 目标文件 eg: c:\temp\abc.txt
     * @param overWrite  如果目标文件存在,是否覆盖
     * @return success
     */
    public static boolean moveFile(String srcFile, String targetFile, boolean overWrite) throws IOException {
        if (srcFile.equals(targetFile)) {
            return true;
        }
        FileObject src = fsMng.resolveFile(srcFile);
        // File (or directory) to be moved
        if (StringUtils.isNotBlank(srcFile) && !src.exists()) {
            throw new IOException("源文件[" + srcFile + "]不存在");
        }
        // Destination directory
        FileObject to = fsMng.resolveFile(targetFile);
        if (to.exists()) {
            if (to.getType() == FileType.FILE) {
                if (overWrite && !to.delete()) {
                    throw new IOException("目标文件[" + targetFile + "]被保护,不能被覆盖!");
                } else if (!overWrite) {
                    throw new IOException("目标文件[" + targetFile + "]已经存在!");
                }
            }
        }
        src.moveTo(to);
        return true;
    }

    public static void print(String path) {
        print(path,null);
    }

    public static void print(String path,  String printPath) {
        try {
            FileSystemManager fsManager = VFS.getManager();
            FileSystemOptions opts = new FileSystemOptions();
            if (path.startsWith("sftp:")) {
                FTPSetting();
            }
            FileObject fileObject = fsManager.resolveFile(path, opts);
            if (fileObject.isFolder()) {
                FileObject[] childs = fileObject.getChildren();
                for (FileObject child : childs) {
                    print(child,printPath);
                }
            } else {
                print(fileObject,printPath);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void print(FileObject fileObject, String printPath) throws Exception {
        if (printPath != null){
            System.setOut(new PrintStream(printPath));
        }
        System.out.println("\n----------");
        System.out.println("url:" + fileObject.getPublicURIString());
        System.out.println("ModifiedTime:" + new Date(fileObject.getContent().getLastModifiedTime()));
        System.out.println("---------- content ----------");
        System.out.println(IOUtils.toString(fileObject.getContent().getInputStream(), "UTF-8"));
    }

    @Before
    public void init() throws FileSystemException {
        vfsInit();
    }
    
    @After
    public void after(){
        fsMng.close();
    }
    
    @Test
    public void testResolve() throws IOException {
        FileObject fo = fsMng.resolveFile("D:\\tem2\\test\\temp2.txt");
        FileObject foFolder = fsMng.resolveFile("D:\\tem2\\test");

        /**
         * 获取属性
         * 结果:
         * org.apache.commons.vfs2.provider.local.LocalFileSystem@4f970963
         * parent:file:///D:/tem2/test
         * name:file:///D:/tem2/test/temp2.txt
         * path:D:\tem2\test\temp2.txt
         * pubURI:file:///D:/tem2/test/temp2.txt
         * URI:file:///D:/tem2/test/temp2.txt
         * URL:file:///D:/tem2/test/temp2.txt
         * 是否文件:true
         * 是否文件夹:false
         * 是否符号链接:false
         * 是否可执行:true
         * 是否隐藏:false
         * type:file
         */
//        System.out.println("/n----------");
//        System.out.println(fo.getFileSystem()); // LocalFileSystem
//        System.out.println("parent:"+fo.getParent().toString());
//        System.out.println("name:"+fo.getName());
//        System.out.println("path:"+fo.getPath());
//        System.out.println("pubURI:"+fo.getPublicURIString());
//        System.out.println("URI:"+fo.getURI().toString());
//        System.out.println("URL:"+fo.getURL());
//
//        System.out.println("是否文件:" + fo.isFile());
//        System.out.println("是否文件夹:" + fo.isFolder());
//        System.out.println("是否符号链接:" + fo.isSymbolicLink());
//        System.out.println("是否可执行:" + fo.isExecutable());
//        System.out.println("是否隐藏:" + fo.isHidden());
//        System.out.println("type:"+fo.getType());

        /**
         * 读取内容
         */
        if (fo.isFile()) {
            FileContent fc = fo.getContent();
            // fc.getInputStream();
            // fc.getByteArray();
            // 获取内容 - 字符串形式
            String content = fc.getString("UTF-8");
            System.out.println(content);
        }

        /**
         * 查找文件  获取子文件
         *
         * 结果:
         * --file:///D:/tem2/test/temp2.txt
         * --file:///D:/tem2/test/test1
         * --file:///D:/tem2/test
         */
//        System.out.println("/n----------");
//        if (foFolder.isFolder()) {
//            FileObject[] files = foFolder.findFiles(Selectors.SELECT_ALL);
//            for (int i = 0; i < files.length; i++) {
//                System.out.println("--" + files[i].getName());
//            }

//            // 获取所有子文件
//            FileObject[] foArr = fo.getChildren();
//            // 获取子文件(名称为test)
//            FileObject test = fo.getChild("a.txt");
//            // 从所有后代中获取类型是文件的文件
//            FileObject[] files = fo.findFiles(Selectors.SELECT_FILES);
//        }


        /**
         * 删除文件
         */
        if (fo.isFolder()) {
            // 删除此文件和所有子文件, 返回删除的数量
            int delCount = fo.deleteAll();// 同fo.delete(Selectors.SELECT_ALL);
			// 只删除所有子文件
            int del2 = fo.delete(Selectors.EXCLUDE_SELF);
            // 只删除直接子文件和空目录
            int del3 = fo.delete(Selectors.SELECT_CHILDREN);
            // 只删除文件
            int del4 = fo.delete(Selectors.SELECT_FILES);
            // 只删除空的子目录
            int del5 = fo.delete(Selectors.SELECT_FOLDERS);
            // 删除目录本身(如果包含子文件则删除失败返回0)
            int del6 = fo.delete(Selectors.SELECT_SELF);

            // 目录不为空则删除失败返回false
            boolean suc = fo.delete();
        } else if (fo.isFile()) {
            // 删除文件本身
            boolean suc = fo.delete();
        }

        // 关闭
        fo.close();
    }

    @Test
    public void testListener() throws IOException {
        // 监听文件创建,修改或删除
        FileSystemManager fsMgr = VFS.getManager();
        String path = "D:\\tem2\\test\\a.txt";
        FileObject fo = fsMgr.toFileObject(new File(path));
        // 添加监听器
        fo.getFileSystem().addListener(fo, new MyListener());
        if (!fo.exists()) {
            fo.createFile();
        }
        fo.setWritable(false, false);
//        fo.delete();
        fo.close();
    }

    private class MyListener implements FileListener {
        @Override
        public void fileCreated(FileChangeEvent event) throws Exception {
            System.out.println("fileCreated:"+event.getFileObject().getName());
        }
        @Override
        public void fileDeleted(FileChangeEvent event) throws Exception {
            System.out.println("fileDeleted:"+event.getFileObject().getName());
        }
        @Override
        public void fileChanged(FileChangeEvent event) throws Exception {
            System.out.println("fileChanged:"+event.getFileObject().getName());
        }
    }

    @Test
    public void testDownForByte(){
        try {
            // 读取
            System.out.println("----------");
//            String url = "file:///D:/tem2/temp.txt";
//			  String url = "zip://file:///D:/tem2/晚安玫瑰.rar!/原始风景.txt";
            String url = "sftp://root:root@192.168.43.128:22/temp/temp.txt";
            byte[] bytes = getFileToByte(url);
            System.out.println("读取:" + url);
            System.out.println("读取到长度:" + bytes.length);
            System.out.println("读取到内容:" + new String(bytes));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void test(){
        try {
            // 写入
            System.out.println("----------");
            String pathUrl = "sftp://root:root@192.168.43.128/temp/temp2.txt";
            System.out.println("写入:" + pathUrl);
            boolean result = uploadFileToByte(pathUrl, "hello temp2 > java:xiaoai".getBytes());
            System.out.println("result:" + (result ? "writer success!" : "writer failed!"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testMethod() throws IOException {
//		  copyFile("D:/tem2/java.jpeg","D:/tem2/javaCope.jpeg",true);
//        moveFile("D:/tem2/javaCope.jpeg","D:/tem2/javaCopeMove.jpeg",true);
//        print("D:\\tem2\\test");
//        print("https://www.baidu.com/index.html");
        print("https://www.baidu.com/index.html","D:\\tem2\\test\\temp2.txt");
    }
}
 类似资料: