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

com.arsframework.util.Files Maven / Gradle / Ivy

package com.arsframework.util;

import java.io.*;
import java.util.*;

import com.arsframework.annotation.Min;
import com.arsframework.annotation.Nonnull;
import com.arsframework.annotation.Nonempty;

/**
 * 文件处理工具类
 *
 * @author yongqiang.wu
 */
public abstract class Files {
    /**
     * 文件查询接口
     */
    public interface Query extends Iterable {
        /**
         * 设置是否展开
         *
         * @param spread true/false
         * @return 文件集合
         */
        Query spread(boolean spread);

        /**
         * 等于
         *
         * @param property 属性
         * @param value    属性值
         * @return 文件集合
         */
        Query eq(Property property, Object value);

        /**
         * 不等于
         *
         * @param property 属性名
         * @param value    属性值
         * @return 文件集合
         */
        Query ne(Property property, Object value);

        /**
         * 大于
         *
         * @param property 属性名
         * @param value    属性值
         * @return 文件集合
         */
        Query gt(Property property, Object value);

        /**
         * 大于或等于
         *
         * @param property 属性名
         * @param value    属性值
         * @return 文件集合
         */
        Query ge(Property property, Object value);

        /**
         * 小于
         *
         * @param property 属性名
         * @param value    属性值
         * @return 文件集合
         */
        Query lt(Property property, Object value);

        /**
         * 小于或等于
         *
         * @param property 属性名
         * @param value    属性值
         * @return 文件集合
         */
        Query le(Property property, Object value);

        /**
         * 属性值在两个值之间
         *
         * @param property 属性名
         * @param low      低值
         * @param high     高值
         * @return 文件集合
         */
        Query between(Property property, Object low, Object high);

        /**
         * 以指定字符串为开始
         *
         * @param property 属性名
         * @param value    属性值
         * @return 文件集合
         */
        Query start(Property property, String value);

        /**
         * 以指定字符串为结束
         *
         * @param property 属性名
         * @param value    属性值
         * @return 文件集合
         */
        Query end(Property property, String value);

        /**
         * 包含指定字符串
         *
         * @param property 属性名
         * @param value    属性值
         * @return 文件集合
         */
        Query like(Property property, String value);

        /**
         * 多个属性升序排序
         *
         * @param properties 属性名数组
         * @return 文件集合
         */
        Query asc(Property... properties);

        /**
         * 多个属性降序排序
         *
         * @param properties 属性名数组
         * @return 文件集合
         */
        Query desc(Property... properties);

        /**
         * 将文件集合对象转换成List对象
         *
         * @return 列表对象
         */
        List list();
    }

    /**
     * 文件查询抽象实现
     */
    public static abstract class AbstractQuery implements Query {
        protected final String path; // 查询操作路径

        private boolean loaded; // 集合是否已加载
        private boolean spread; // 是否展开
        private List orders = new LinkedList<>(); // 排序条件
        private List describes = Collections.emptyList(); // 缓存数据
        private List conditions = new LinkedList<>(); // 查询条件

        @Nonnull
        public AbstractQuery(String path) {
            this.path = Strings.toRealPath(path);
        }

        /**
         * 执行文件查询
         *
         * @param path       文件查询相对路径
         * @param spread     是否展开
         * @param conditions 查询条件数组
         * @return 文件描述列表
         */
        protected abstract List execute(String path, boolean spread, Condition... conditions);

        @Override
        public Iterator iterator() {
            return this.list().iterator();
        }

        @Override
        public Query spread(boolean spread) {
            this.spread = spread;
            return this;
        }

        @Override
        public Query eq(Property property, Object value) {
            this.conditions.add(Files.eq(property, value));
            return this;
        }

        @Override
        public Query ne(Property property, Object value) {
            this.conditions.add(Files.ne(property, value));
            return this;
        }

        @Override
        public Query gt(Property property, Object value) {
            this.conditions.add(Files.gt(property, value));
            return this;
        }

        @Override
        public Query ge(Property property, Object value) {
            this.conditions.add(Files.ge(property, value));
            return this;
        }

        @Override
        public Query lt(Property property, Object value) {
            this.conditions.add(Files.lt(property, value));
            return this;
        }

        @Override
        public Query le(Property property, Object value) {
            this.conditions.add(Files.le(property, value));
            return this;
        }

        @Override
        public Query between(Property property, Object low, Object high) {
            this.conditions.add(Files.between(property, low, high));
            return this;
        }

        @Override
        public Query start(Property property, String value) {
            this.conditions.add(Files.like(property, value, Files.Like.Position.BEGIN));
            return this;
        }

        @Override
        public Query end(Property property, String value) {
            this.conditions.add(Files.like(property, value, Files.Like.Position.END));
            return this;
        }

        @Override
        public Query like(Property property, String value) {
            this.conditions.add(Files.like(property, value, Files.Like.Position.ANY));
            return this;
        }

        @Override
        @Nonnull
        public Query asc(Property... properties) {
            if (properties.length > 0) {
                for (Property property : properties) {
                    this.orders.add(Files.asc(property));
                }
            }
            return this;
        }

        @Override
        @Nonnull
        public Query desc(Property... properties) {
            if (properties.length > 0) {
                for (Property property : properties) {
                    this.orders.add(Files.desc(property));
                }
            }
            return this;
        }

        @Override
        public List list() {
            if (!this.loaded) {
                this.describes = this.execute(this.path, this.spread, this.conditions.toArray(new Condition[0]));
                if (!this.orders.isEmpty()) {
                    Files.sort(this.describes, this.orders.toArray(new Order[0]));
                }
                this.loaded = true;
            }
            return this.describes;
        }

        @Override
        public String toString() {
            return this.list().toString();
        }
    }

    /**
     * 磁盘文件查询集合实现
     */
    public static class DiskQuery extends AbstractQuery {

        public DiskQuery(String path) {
            super(path);
        }

        @Override
        public List execute(String path, boolean spread, Condition... conditions) {
            List describes = new LinkedList<>();
            new File(path).listFiles((file) -> {
                Describe describe = Describe.parse(file);
                if (Files.isSatisfy(describe, conditions)) {
                    describes.add(describe);
                }
                if (spread && describe.directory) {
                    describes.addAll(execute(describe.path, true, conditions));
                }
                return false;
            });
            return describes;
        }

    }

    /**
     * 创建文件目录
     *
     * @param file 文件对象
     * @return 文件目录对象
     */
    public static File mkdirs(File file) {
        File path = file == null ? null : file.getParentFile();
        if (path != null && !path.exists()) {
            path.mkdirs();
        }
        return path;
    }

    /**
     * 递归删除文件/文件目录
     *
     * @param file 源文件/文件目录
     */
    public static void delete(File file) {
        if (file != null && file.exists()) {
            if (file.isDirectory()) {
                for (File child : file.listFiles()) {
                    delete(child);
                }
            }
            file.delete();
        }
    }

    /**
     * 递归拷贝文件/文件目录
     *
     * @param source 源文件/文件目录
     * @param target 目标文件目录
     * @throws IOException IO操作异常
     */
    @Nonnull
    public static void copy(File source, File target) throws IOException {
        if (!source.equals(target)) {
            if (source.isDirectory()) {
                File path = new File(target, source.getName());
                if (!path.exists()) {
                    path.mkdirs();
                }
                for (File child : source.listFiles()) {
                    copy(child, path);
                }
            } else {
                Streams.write(source, new File(target, source.getName()));
            }
        }
    }

    /**
     * 递归移动文件/文件目录
     *
     * @param source 源文件/文件目录
     * @param target 目标文件目录
     */
    @Nonnull
    public static void move(File source, File target) {
        if (!source.equals(target)) {
            if (source.isDirectory()) {
                File path = new File(target, source.getName());
                if (!path.exists()) {
                    path.mkdirs();
                }
                for (File child : source.listFiles()) {
                    move(child, path);
                }
                source.delete();
            } else {
                source.renameTo(new File(target, source.getName()));
            }
        }
    }

    /**
     * 文件重命名
     *
     * @param file 文件对象
     * @param name 重命名名称
     */
    @Nonnull
    public static void rename(File file, String name) {
        file.renameTo(new File(file.getParent(), name));
    }

    /**
     * 获取文件名称
     *
     * @param path 文件路径
     * @return 文件名称
     */
    @Nonnull
    public static String getName(String path) {
        int end = path.length();
        for (int i = end - 1; i > -1; i--) {
            if (path.charAt(i) == '\\' || path.charAt(i) == '/') {
                if (i < end - 1) {
                    return path.substring(i + 1, end);
                }
                end--;
            }
        }
        String name = end == path.length() ? path : path.substring(0, end);
        return name.isEmpty() ? null : name;
    }

    /**
     * 获取文件后缀名
     *
     * @param path 文件路径
     * @return 后缀名
     */
    @Nonnull
    public static String getSuffix(String path) {
        int index = path.lastIndexOf('.');
        if (index < 0) {
            return null;
        }
        int end = path.length() - 1;
        for (; end > -1 && (path.charAt(end) == '\\' || path.charAt(end) == '/'); end--) ;
        String suffix = path.substring(index + 1, end + 1);
        return suffix.isEmpty() ? null : suffix;
    }

    /**
     * 文件查询
     *
     * @param path 文件目录
     * @return 查询对象
     */
    public static Query query(String path) {
        return new DiskQuery(path);
    }

    /**
     * 文件/文件目录属性
     *
     * @param  属性类型
     */
    public static final class Property {
        /**
         * 属性类型
         */
        public final Class type;

        /**
         * 属性名称
         */
        public final String name;

        @Nonempty
        private Property(Class type, String name) {
            this.name = name;
            this.type = type;
        }

        /**
         * 文件/文件目录名称属性
         */
        public static final Property NAME = new Property<>(String.class, "name");

        /**
         * 文件/文件目录大小属性
         */
        public static final Property SIZE = new Property<>(Long.class, "size");

        /**
         * 文件/文件目录最后修改时间属性
         */
        public static final Property MODIFIED = new Property<>(Long.class, "modified");

        /**
         * 是否为文件目录属性
         */
        public static final Property DIRECTORY = new Property<>(Boolean.class, "directory");

        @Override
        public boolean equals(Object other) {
            return other instanceof Property && this.type == ((Property) other).type && this.name.equals(((Property) other).name);
        }

        @Override
        public int hashCode() {
            return Arrays.hashCode(new Object[]{this.name, this.type});
        }
    }

    /**
     * 文件比较条件接口
     */
    public interface Condition {
    }

    /**
     * 文件描述对象
     */
    public static class Describe implements Comparable, Serializable {
        private static final long serialVersionUID = 1L;

        /**
         * 文件/文件目录相对路径
         */
        public final String path;

        /**
         * 文件/文件目录名称
         */
        public final String name;

        /**
         * 文件/文件目录大小
         */
        public final long size;

        /**
         * 文件/文件目录最后修改时间
         */
        public final long modified;

        /**
         * 是否为文件目录
         */
        public final boolean directory;

        @Nonnull
        public Describe(String path, String name, @Min(0) long size, long modified, boolean directory) {
            this.path = path;
            this.name = name;
            this.size = size;
            this.modified = modified;
            this.directory = directory;
        }

        @Override
        public int compareTo(Describe other) {
            return this.path.compareTo(other.path);
        }

        @Override
        public boolean equals(Object other) {
            return other instanceof Describe && this.path.equals(((Describe) other).path);
        }

        @Override
        public int hashCode() {
            return 31 + this.path.hashCode();
        }

        @Override
        public String toString() {
            return this.path;
        }

        /**
         * 文件/文件描述转换
         *
         * @param file 文件对象
         * @return 文件描述对象
         */
        @Nonnull
        public static Describe parse(File file) {
            return new Describe(file.getPath().replace("\\", "/"),
                    file.getName(), file.length(), file.lastModified(), file.isDirectory());
        }
    }

    /**
     * 等于条件
     *
     * @param  数据类型
     */
    public static class Equal implements Condition {
        public final Property property; // 比较属性
        public final T[] values; // 比较值数组

        @Nonnull
        public Equal(Property property, T... values) {
            this.property = property;
            this.values = values;
        }

    }

    /**
     * 不等于
     *
     * @param  数据类型
     */
    public static class NotEqual implements Condition {
        public final Property property; // 比较属性
        public final T[] values; // 比较值数组

        @Nonnull
        public NotEqual(Property property, T... values) {
            this.property = property;
            this.values = values;
        }

    }

    /**
     * 大于
     *
     * @param  数据类型
     */
    public static class Large implements Condition {
        public final Property property; // 比较属性
        public final T value; // 比较值

        @Nonnull
        public Large(Property property, T value) {
            this.property = property;
            this.value = value;
        }

    }

    /**
     * 大于或等于
     *
     * @param  数据类型
     */
    public static class LargeEqual implements Condition {
        public final Property property; // 比较属性
        public final T value; // 比较值

        @Nonnull
        public LargeEqual(Property property, T value) {
            this.property = property;
            this.value = value;
        }

    }

    /**
     * 小于
     *
     * @param  数据类型
     */
    public static class Less implements Condition {
        public final Property property; // 比较属性
        public final T value; // 比较值

        @Nonnull
        public Less(Property property, T value) {
            this.property = property;
            this.value = value;
        }

    }

    /**
     * 小于或等于
     *
     * @param  数据类型
     */
    public static class LessEqual implements Condition {
        public final Property property; // 比较属性
        public final T value; // 比较值

        @Nonnull
        public LessEqual(Property property, T value) {
            this.property = property;
            this.value = value;
        }

    }

    /**
     * 大于和小于
     *
     * @param  数据类型
     */
    public static class Between implements Condition {
        public final Property property; // 比较属性
        public final T min; // 最小值
        public final T max; // 最大值

        @Nonnull
        public Between(Property property, T min, T max) {
            this.property = property;
            this.min = min;
            this.max = max;
        }

    }

    /**
     * 模糊匹配
     *
     * @param  数据类型
     */
    public static class Like implements Condition {
        public final Property property; // 比较属性
        public final T value; // 比较值
        public final Position position; // 比较位置

        public Like(Property property, T value) {
            this(property, value, Position.ANY);
        }

        @Nonnull
        public Like(Property property, T value, Position position) {
            this.property = property;
            this.value = value;
            this.position = position;
        }

        /**
         * 匹配位置
         */
        public enum Position {
            /**
             * 开始位置
             */
            BEGIN,

            /**
             * 结束位置
             */
            END,

            /**
             * 任何位置
             */
            ANY;

        }

    }

    /**
     * 排序条件
     */
    public static class Order implements Condition {
        public final Property property; // 排序属性

        @Nonnull
        public Order(Property property) {
            this.property = property;
        }

    }

    /**
     * 升序排序条件
     */
    public static class Asc extends Order {

        public Asc(Property property) {
            super(property);
        }

    }

    /**
     * 降序排序条件
     */
    public static class Desc extends Order {

        public Desc(Property property) {
            super(property);
        }

    }

    /**
     * 等于
     *
     * @param property 属性
     * @param values   属性值数组
     * @param       数据类型
     * @return 条件对象
     */
    public static  Equal eq(Property property, T... values) {
        return new Equal(property, values);
    }

    /**
     * 不等于
     *
     * @param property 属性
     * @param values   属性值数组
     * @param       数据类型
     * @return 条件对象
     */
    public static  NotEqual ne(Property property, T... values) {
        return new NotEqual(property, values);
    }

    /**
     * 大于
     *
     * @param property 属性
     * @param value    属性值
     * @param       数据类型
     * @return 条件对象
     */
    public static  Large gt(Property property, T value) {
        return new Large(property, value);
    }

    /**
     * 大于或等于
     *
     * @param property 属性
     * @param value    属性值
     * @param       数据类型
     * @return 条件对象
     */
    public static  LargeEqual ge(Property property, T value) {
        return new LargeEqual(property, value);
    }

    /**
     * 小于
     *
     * @param property 属性
     * @param value    属性值
     * @param       数据类型
     * @return 条件对象
     */
    public static  Less lt(Property property, T value) {
        return new Less(property, value);
    }

    /**
     * 小于或等于
     *
     * @param property 属性
     * @param value    属性值
     * @param       数据类型
     * @return 条件对象
     */
    public static  LessEqual le(Property property, T value) {
        return new LessEqual(property, value);
    }

    /**
     * 属性值在两个值之间
     *
     * @param property 属性
     * @param min      最小值
     * @param max      最大值
     * @param       数据类型
     * @return 条件对象
     */
    public static  Between between(Property property, T min, T max) {
        return new Between(property, min, max);
    }

    /**
     * 包含指定字符串
     *
     * @param property 属性
     * @param value    属性值
     * @param       数据类型
     * @return 条件对象
     */
    public static  Like like(Property property, T value) {
        return like(property, value, Like.Position.ANY);
    }

    /**
     * 包含指定字符串
     *
     * @param property 属性
     * @param value    属性值
     * @param position 匹配位置
     * @param       数据类型
     * @return 条件对象
     */
    public static  Like like(Property property, T value, Like.Position position) {
        return new Like(property, value, position);
    }

    /**
     * 升序条件
     *
     * @param property 属性
     * @return 条件对象
     */
    public static Asc asc(Property property) {
        return new Asc(property);
    }

    /**
     * 降序条件
     *
     * @param property 属性
     * @return 条件对象
     */
    public static Desc desc(Property property) {
        return new Desc(property);
    }

    /**
     * 判断文件描述是否满足小于条件
     *
     * @param describe 文件描述对象
     * @param less     小于条件
     * @return true/false
     */
    @Nonnull
    public static boolean isSatisfy(Describe describe, Less less) {
        return (less.property == Property.NAME && describe.name.compareToIgnoreCase((String) less.value) < 0)
                || (less.property == Property.SIZE && describe.size < (long) less.value)
                || (less.property == Property.MODIFIED && describe.modified < (long) less.value);
    }

    /**
     * 判断文件描述是否满足模糊匹配条件
     *
     * @param describe 文件描述对象
     * @param like     模糊匹配条件
     * @return true/false
     */
    @Nonnull
    public static boolean isSatisfy(Describe describe, Like like) {
        if (like.property == Property.NAME) {
            String source = describe.name.toUpperCase();
            String value = ((String) like.value).toUpperCase();
            return (like.position == Like.Position.BEGIN && source.indexOf(value) == 0)
                    || (like.position == Like.Position.END && source.lastIndexOf(value) == source.length() - value.length())
                    || (like.position == Like.Position.ANY && source.indexOf(value) > -1);
        }
        return true;
    }

    /**
     * 判断文件描述是否满足等于条件
     *
     * @param describe 文件描述对象
     * @param equal    等于条件
     * @return true/false
     */
    @Nonnull
    public static boolean isSatisfy(Describe describe, Equal equal) {
        for (Object value : equal.values) {
            if ((equal.property == Property.NAME && describe.name.equalsIgnoreCase((String) value))
                    || (equal.property == Property.SIZE && describe.size == (long) value)
                    || (equal.property == Property.MODIFIED && describe.modified == (long) value)
                    || (equal.property == Property.DIRECTORY && describe.directory == (boolean) value)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断文件描述是否满足大于条件
     *
     * @param describe 文件描述对象
     * @param large    大于条件
     * @return true/false
     */
    @Nonnull
    public static boolean isSatisfy(Describe describe, Large large) {
        return (large.property == Property.NAME && describe.name.compareToIgnoreCase((String) large.value) > 0)
                || (large.property == Property.SIZE && describe.size > (long) large.value)
                || (large.property == Property.MODIFIED && describe.modified > (long) large.value);
    }

    /**
     * 判断文件描述是否满足大于小于条件
     *
     * @param describe 文件描述对象
     * @param between  大于小于条件
     * @return true/false
     */
    @Nonnull
    public static boolean isSatisfy(Describe describe, Between between) {
        return (between.property == Property.NAME && describe.name.compareToIgnoreCase((String) between.min) >= 0
                && describe.name.compareToIgnoreCase((String) between.max) <= 0)
                || (between.property == Property.SIZE
                && describe.size >= (long) between.min && describe.size <= (long) between.max)
                || (between.property == Property.MODIFIED
                && describe.modified >= (long) between.min && describe.modified <= (long) between.max);
    }

    /**
     * 判断文件描述是否满足不等于条件
     *
     * @param describe 文件描述对象
     * @param notEqual 不等于条件
     * @return true/false
     */
    @Nonnull
    public static boolean isSatisfy(Describe describe, NotEqual notEqual) {
        return !isSatisfy(describe, new Equal(notEqual.property, notEqual.values));
    }

    /**
     * 判断文件描述是否满足小于或等于条件
     *
     * @param describe  文件描述对象
     * @param lessEqual 小于或等于条件
     * @return true/false
     */
    @Nonnull
    public static boolean isSatisfy(Describe describe, LessEqual lessEqual) {
        return (lessEqual.property == Property.NAME && describe.name.compareToIgnoreCase((String) lessEqual.value) <= 0)
                || (lessEqual.property == Property.SIZE && describe.size <= (long) lessEqual.value)
                || (lessEqual.property == Property.MODIFIED && describe.modified <= (long) lessEqual.value);
    }

    /**
     * 判断文件描述是否满足大于或等于条件
     *
     * @param describe   文件描述对象
     * @param largeEqual 大于或等于条件
     * @return true/false
     */
    @Nonnull
    public static boolean isSatisfy(Describe describe, LargeEqual largeEqual) {
        return (largeEqual.property == Property.NAME && describe.name.compareToIgnoreCase((String) largeEqual.value) >= 0)
                || (largeEqual.property == Property.SIZE && describe.size >= (long) largeEqual.value)
                || (largeEqual.property == Property.MODIFIED && describe.modified >= (long) largeEqual.value);
    }

    /**
     * 判断文件描述是否满足查询条件
     *
     * @param describe   文件描述对象
     * @param conditions 查询条件数组
     * @return true/false
     */
    @Nonnull
    public static boolean isSatisfy(Describe describe, Condition... conditions) {
        for (Condition condition : conditions) {
            if (condition instanceof Less && !isSatisfy(describe, (Less) condition)) {
                return false;
            } else if (condition instanceof Like && !isSatisfy(describe, (Like) condition)) {
                return false;
            } else if (condition instanceof Equal && !isSatisfy(describe, (Equal) condition)) {
                return false;
            } else if (condition instanceof Large && !isSatisfy(describe, (Large) condition)) {
                return false;
            } else if (condition instanceof Between && !isSatisfy(describe, (Between) condition)) {
                return false;
            } else if (condition instanceof NotEqual && !isSatisfy(describe, (NotEqual) condition)) {
                return false;
            } else if (condition instanceof LessEqual && !isSatisfy(describe, (LessEqual) condition)) {
                return false;
            } else if (condition instanceof LargeEqual && !isSatisfy(describe, (LargeEqual) condition)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 文件描述比较
     *
     * @param describe 比较文件描述对象
     * @param other    被比较文件描述对象
     * @param orders   排序对象
     * @return 比较结果
     */
    public static int compare(Describe describe, Describe other, @Nonnull Order... orders) {
        if (describe != null && other != null) {
            for (Order order : orders) {
                int compare = 0;
                if (order.property == Property.NAME) {
                    compare = describe.name.compareTo(other.name);
                } else if (order.property == Property.SIZE) {
                    compare = describe.size < other.size ? -1 : describe.size == other.size ? 0 : 1;
                } else if (order.property == Property.MODIFIED) {
                    compare = describe.modified < other.modified ? -1 : describe.modified == other.modified ? 0 : 1;
                } else if (order.property == Property.DIRECTORY) {
                    compare = describe.directory && !other.directory ? -1 : describe.directory == other.directory ? 0 : 1;
                }
                if (compare != 0) {
                    return order instanceof Asc ? compare : -compare;
                }
            }
        }
        return describe == null && other == null ? 0 : describe == null ? -1 : other == null ? 1 : 0;
    }

    /**
     * 对文件描述列表排序
     *
     * @param describes 文件描述对象数组
     * @param orders    排序对象数组
     */
    @Nonnull
    public static void sort(Describe[] describes, Order... orders) {
        Arrays.sort(describes, (Describe o1, Describe o2) -> compare(o1, o2, orders));
    }

    /**
     * 对文件描述列表排序
     *
     * @param describes 文件描述对象列表
     * @param orders    排序对象数组
     */
    @Nonnull
    public static void sort(List describes, Order... orders) {
        Collections.sort(describes, (Describe o1, Describe o2) -> compare(o1, o2, orders));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy