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

com.neko233.toolchain.common.file.FileUtils233 Maven / Gradle / Ivy

package com.neko233.toolchain.common.file;


import com.neko233.toolchain.common.base.CollectionUtils233;
import com.neko233.toolchain.common.base.DataSizeUtils233;
import com.neko233.toolchain.common.file.visitor.FileVisitorForAccumulate;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOExceptionList;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.file.Counters;
import org.apache.commons.io.file.PathUtils;
import org.apache.commons.io.file.StandardDeleteOption;

import java.io.*;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileVisitOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author SolarisNeko
 */
@Slf4j
public class FileUtils233 {

    public static List readLines(final File file, final Charset charset) throws IOException {
        try (InputStream inputStream = openInputStream(file)) {
            return readLines(inputStream, chooseCharset(charset));
        }
    }

    public static List readLines(final InputStream input, final Charset charset) throws IOException {
        final InputStreamReader reader = new InputStreamReader(input, chooseCharset(charset));
        return readLines(reader);
    }

    public static List readLines(final Reader reader) throws IOException {
        final BufferedReader bufReader = toBufferedReader(reader);
        final List lineList = new ArrayList<>();
        String line;
        while ((line = bufReader.readLine()) != null) {
            lineList.add(line);
        }
        return lineList;
    }


    // ----------- base ---------------

    public static BufferedReader toBufferedReader(final Reader reader) {
        return reader instanceof BufferedReader ? (BufferedReader) reader : new BufferedReader(reader);
    }

    public static FileInputStream openInputStream(final File file) throws IOException {
        Objects.requireNonNull(file, "file");
        return new FileInputStream(file);
    }

    private static Charset chooseCharset(Charset charset) {
        return charset == null ? Charset.defaultCharset() : charset;
    }

    /**
     * 读取 properties file
     *
     * @param propsFilename 文件名
     * @return Properties
     */
    public static Properties readPropertiesFromFilename(String propsFilename) {
        Properties archProps = new Properties();
        LinkedHashSet list = Stream.of(
                        Thread.currentThread().getContextClassLoader(),
                        ClassLoader.getSystemClassLoader(),
                        FileUtils233.class.getClassLoader()
                )
                .collect(Collectors.toCollection(LinkedHashSet::new));
        for (ClassLoader loader : list) {
            if (readPropertiesFromClassLoader(propsFilename, archProps, loader)) {
                return archProps;
            }
        }
        log.warn("Failed to load configuration file from classloader: {}", propsFilename);
        return archProps;
    }


    /**
     * ClassLoader 加载 properties 文件
     *
     * @param propsFilename
     * @param archProps
     * @param loader
     * @return
     */
    private static boolean readPropertiesFromClassLoader(String propsFilename, Properties archProps,
                                                         ClassLoader loader) {
        if (loader == null) {
            return false;
        }
        // Load the configuration file from the classLoader
        try {
            List resources = Collections.list(loader.getResources(propsFilename));
            if (resources.isEmpty()) {
                log.debug("No {} file found from ClassLoader {}", propsFilename, loader);
                return false;
            }
            if (resources.size() > 1) {
                log.warn("Configuration conflict: there is more than one {} file on the classpath: {}", propsFilename,
                        resources);
            }
            try (InputStream in = resources.get(0).openStream()) {
                if (in != null) {
                    archProps.load(in);
                }
            }
            return true;
        } catch (IOException e) {
            return false;
        }
    }


    public static List showFiles(final File fileOrDir) throws IOException {
        return showFiles(fileOrDir, false, null);
    }

    public static List showFiles(final File fileOrDir, final boolean isRecursive) throws IOException {
        return showFiles(fileOrDir, isRecursive, null);
    }

    /**
     * 显示文件
     *
     * @param fileOrDir   文件/目录
     * @param isRecursive 是否递归
     * @param suffixes    后缀名称. example = ".txt"
     * @return 纯文件 (不包含 dir)
     * @throws IOException
     */
    public static List showFiles(final File fileOrDir, final boolean isRecursive, final List suffixes)
            throws IOException {
        final List suffixList = Optional.ofNullable(suffixes).orElse(new ArrayList<>());

        if (fileOrDir == null) {
            return new ArrayList<>();
        }

        File dir = fileOrDir;
        if (fileOrDir.isFile()) {
            return Collections.singletonList(fileOrDir);
        }

        Path dirPath = dir.toPath();

        // single
        if (!isRecursive) {
            File[] array = dir.listFiles();
            if (array == null) {
                return new ArrayList<>();
            }
            return Arrays.stream(array).filter(File::isFile).collect(Collectors.toList());
        }


        final EnumSet fileVisitOptions = EnumSet.of(FileVisitOption.FOLLOW_LINKS);

        final FileVisitorForAccumulate visitor = new FileVisitorForAccumulate();
        Files.walkFileTree(dirPath, fileVisitOptions, Integer.MAX_VALUE, visitor);
        List justFileList = visitor.getJustFileList();
        return Optional.ofNullable(justFileList)
                .orElse(new ArrayList<>())
                .stream()
                .filter(file -> {
                    if (CollectionUtils233.isEmpty(suffixList)) {
                        return true;
                    }
                    // filter suffix
                    for (String fileSuffix : suffixList) {
                        return file.getName().endsWith(fileSuffix);
                    }
                    return false;
                })
                .collect(Collectors.toList());
    }

    private static String getFileTreeString(File f, int level) {
        // 返回一个抽象路径名数组,这些路径名表示此抽象路径名所表示目录中地文件
        File[] childs = f.listFiles();
        StringBuilder fileTreeBuilder = new StringBuilder();
        for (int i = 0; i < childs.length; i++) {
            // 打印前缀
            for (int j = 0; j < level; j++) {
                if (j == 0) {
                    fileTreeBuilder.append("|_");
                } else {
                    fileTreeBuilder.append("_");
                }
            }

            if (childs[i].isDirectory()) { //
                fileTreeBuilder.append(childs[i].getName());// 打印子文件地名字
                fileTreeBuilder.append(System.lineSeparator());

                String subFileTree = getFileTreeString(childs[i], level + 1);
                fileTreeBuilder.append(subFileTree);
            } else {
                // 如果是文件把大小也打印出来
                fileTreeBuilder.append(childs[i].getName()).append("\t\t\t\t\t")
                        // size
                        .append(DataSizeUtils233.toHumanFormatByByte(childs[i].length()));
                fileTreeBuilder.append(System.lineSeparator());
            }

        }
        return fileTreeBuilder.toString();
    }


    /**
     * 线性化文件树, Tree -> List
     *
     * @param startDir 需要遍历的文件夹
     * @return file tree -> all file List
     */
    public static List liner(String startDir) {
        List fileList = new ArrayList<>();

        File directory = new File(startDir);
        if (!directory.exists() || !directory.isDirectory()) {
            return fileList;
        }

        File[] files = directory.listFiles();
        if (files == null) {
            return new ArrayList<>();
        }
        for (File file : files) {
            if (file.isDirectory()) {
                // loop
                List liner = liner(file.getPath());
                fileList.addAll(liner);
                continue;
            }
            if (!file.isFile()) {
                continue;
            }
            if (file.length() == 0) {
                continue;
            }
            fileList.add(file);
        }
        return fileList;
    }


    /**
     * 新建文件 if 不存在
     *
     * @param newFile 新文件
     */
    public static boolean createFileIfNotExists(File newFile) throws IOException {
        if (newFile.exists()) {
            return false;
        }
        newFile.createNewFile();
        return true;
    }

    public static String readAllContent(File file) throws IOException {
        return readAllContent(file, StandardCharsets.UTF_8);
    }

    public static String readAllContent(File file, Charset charset) throws IOException {
        if (file == null || !file.exists()) {
            return null;
        }
        return readLines(file, charset)
                .stream()
                .collect(Collectors.joining(System.lineSeparator()));
    }


    public static void write(final File file, final CharSequence data) throws IOException {
        write(file, data, StandardCharsets.UTF_8);
    }

    /**
     * default Append !
     *
     * @param file    文本
     * @param data    数据
     * @param charset 编码
     * @throws IOException
     */
    public static void write(final File file, final CharSequence data, final Charset charset) throws IOException {
        write(file, data, charset, true);
    }

    /**
     * Writes a CharSequence to a file creating the file if it does not exist.
     *
     * @param file    the file to write
     * @param data    the content to write to the file
     * @param charset the charset to use, {@code null} means platform default
     * @param append  if {@code true}, then the data will be added to the
     *                end of the file rather than overwriting
     * @throws IOException in case of an I/O error
     */
    public static void write(final File file, final CharSequence data, final Charset charset, final boolean append)
            throws IOException {
        writeStringToFile(file, Objects.toString(data, null), charset, append);
    }


    /**
     * 写入文本到文件
     *
     * @param file
     * @param data
     * @param charset
     * @param append
     * @throws IOException
     */
    public static void writeStringToFile(final File file, final String data, final Charset charset,
                                         final boolean append) throws IOException {
        try (OutputStream out = openOutputStream(file, append)) {
            IoUtils233.write(data, out, charset);
        }
    }

    public static FileOutputStream openOutputStream(final File file, final boolean append) throws IOException {
        Objects.requireNonNull(file, "file");
        if (file.exists()) {
            requireFile(file, "file");
            requireCanWrite(file, "file");
        } else {
            createParentDirectories(file);
        }
        return new FileOutputStream(file, append);
    }

    /**
     * Requires that the given {@code File} is a file.
     *
     * @param file The {@code File} to check.
     * @param name The parameter name to use in the exception message.
     * @return the given file.
     * @throws NullPointerException     if the given {@code File} is {@code null}.
     * @throws IllegalArgumentException if the given {@code File} does not exist or is not a directory.
     */
    private static File requireFile(final File file, final String name) {
        Objects.requireNonNull(file, name);
        if (!file.isFile()) {
            throw new IllegalArgumentException("Parameter '" + name + "' is not a file: " + file);
        }
        return file;
    }

    /**
     * 文件必须可写入
     *
     * @param file The file to test.
     * @param name The parameter name to use in the exception message.
     * @throws NullPointerException     if the given {@code File} is {@code null}.
     * @throws IllegalArgumentException if the file is not writable.
     */
    private static void requireCanWrite(final File file, final String name) {
        Objects.requireNonNull(file, "file");
        if (!file.canWrite()) {
            throw new IllegalArgumentException("File parameter '" + name + " is not writable: '" + file + "'");
        }
    }

    /**
     * Creates all parent directories for a File object.
     *
     * @param file the File that may need parents, may be null.
     * @return The parent directory, or {@code null} if the given file does not name a parent
     * @throws IOException if the directory was not created along with all its parent directories.
     * @throws IOException if the given file object is not null and not a directory.
     * @since 2.9.0
     */
    public static File createParentDirectories(final File file) throws IOException {
        return createAllParentDir(getParentFile(file));
    }

    private static File getParentFile(final File file) {
        return file == null ? null : file.getParentFile();
    }

    /**
     * Calls {@link File#mkdirs()} and throws an exception on failure.
     *
     * @param directory the receiver for {@code mkdirs()}, may be null.
     * @return the given file, may be null.
     * @throws IOException       if the directory was not created along with all its parent directories.
     * @throws IOException       if the given file object is not a directory.
     * @throws SecurityException See {@link File#mkdirs()}.
     * @see File#mkdirs()
     */
    private static File createAllParentDir(final File directory) throws IOException {
        if ((directory != null)
                && (!directory.mkdirs()
                && !directory.isDirectory())) {
            throw new IOException("Cannot create directory '" + directory + "'.");
        }
        return directory;
    }


    /**
     * Writes the {@code toString()} value of each item in a collection to
     * the specified {@code File} line by line.
     * The default VM encoding and the default line ending will be used.
     *
     * @param file  the file to write to
     * @param lines the lines to write, {@code null} entries produce blank lines
     * @throws IOException in case of an I/O error
     * @since 1.3
     */
    public static void writeLines(final File file, final Collection lines) throws IOException {
        writeLines(file, null, lines, null, false);
    }

    /**
     * Writes the {@code toString()} value of each item in a collection to
     * the specified {@code File} line by line.
     * The default VM encoding and the default line ending will be used.
     *
     * @param file   the file to write to
     * @param lines  the lines to write, {@code null} entries produce blank lines
     * @param append if {@code true}, then the lines will be added to the
     *               end of the file rather than overwriting
     * @throws IOException in case of an I/O error
     * @since 2.1
     */
    public static void writeLines(final File file, final Collection lines, final boolean append) throws IOException {
        writeLines(file, null, lines, null, append);
    }

    /**
     * Writes the {@code toString()} value of each item in a collection to
     * the specified {@code File} line by line.
     * The default VM encoding and the specified line ending will be used.
     *
     * @param file       the file to write to
     * @param lines      the lines to write, {@code null} entries produce blank lines
     * @param lineEnding the line separator to use, {@code null} is system default
     * @throws IOException in case of an I/O error
     * @since 1.3
     */
    public static void writeLines(final File file, final Collection lines, final String lineEnding)
            throws IOException {
        writeLines(file, null, lines, lineEnding, false);
    }


    /**
     * Writes the {@code toString()} value of each item in a collection to
     * the specified {@code File} line by line.
     * The default VM encoding and the specified line ending will be used.
     *
     * @param file       the file to write to
     * @param lines      the lines to write, {@code null} entries produce blank lines
     * @param lineEnding the line separator to use, {@code null} is system default
     * @param append     if {@code true}, then the lines will be added to the
     *                   end of the file rather than overwriting
     * @throws IOException in case of an I/O error
     * @since 2.1
     */
    public static void writeLines(final File file, final Collection lines, final String lineEnding,
                                  final boolean append) throws IOException {
        writeLines(file, null, lines, lineEnding, append);
    }

    /**
     * Writes the {@code toString()} value of each item in a collection to
     * the specified {@code File} line by line.
     * The specified character encoding and the default line ending will be used.
     * 

* NOTE: As from v1.3, the parent directories of the file will be created * if they do not exist. *

* * @param file the file to write to * @param charsetName the name of the requested charset, {@code null} means platform default * @param lines the lines to write, {@code null} entries produce blank lines * @throws IOException in case of an I/O error * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM * @since 1.1 */ public static void writeLines(final File file, final String charsetName, final Collection lines) throws IOException { writeLines(file, charsetName, lines, null, false); } /** * Writes the {@code toString()} value of each item in a collection to * the specified {@code File} line by line, optionally appending. * The specified character encoding and the default line ending will be used. * * @param file the file to write to * @param charsetName the name of the requested charset, {@code null} means platform default * @param lines the lines to write, {@code null} entries produce blank lines * @param append if {@code true}, then the lines will be added to the * end of the file rather than overwriting * @throws IOException in case of an I/O error * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM * @since 2.1 */ public static void writeLines(final File file, final String charsetName, final Collection lines, final boolean append) throws IOException { writeLines(file, charsetName, lines, null, append); } /** * Writes the {@code toString()} value of each item in a collection to * the specified {@code File} line by line. * The specified character encoding and the line ending will be used. *

* NOTE: As from v1.3, the parent directories of the file will be created * if they do not exist. *

* * @param file the file to write to * @param charsetName the name of the requested charset, {@code null} means platform default * @param lines the lines to write, {@code null} entries produce blank lines * @param lineEnding the line separator to use, {@code null} is system default * @throws IOException in case of an I/O error * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM * @since 1.1 */ public static void writeLines(final File file, final String charsetName, final Collection lines, final String lineEnding) throws IOException { writeLines(file, charsetName, lines, lineEnding, false); } /** * Writes the {@code toString()} value of each item in a collection to * the specified {@code File} line by line. * The specified character encoding and the line ending will be used. * * @param file the file to write to * @param charsetName the name of the requested charset, {@code null} means platform default * @param lines the lines to write, {@code null} entries produce blank lines * @param lineEnding the line separator to use, {@code null} is system default * @param append if {@code true}, then the lines will be added to the * end of the file rather than overwriting * @throws IOException in case of an I/O error * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM */ public static void writeLines(final File file, final String charsetName, final Collection lines, final String lineEnding, final boolean append ) throws IOException { try (OutputStream out = new BufferedOutputStream(openOutputStream(file, append))) { IOUtils.writeLines(lines, lineEnding, out, charsetName); } } public static boolean deleteQuietly(final File file) { if (file == null) { return false; } try { if (file.isDirectory()) { cleanDirectory(file); } } catch (final Exception ignored) { // ignore } try { return file.delete(); } catch (final Exception ignored) { return false; } } public static void cleanDirectory(final File directory) throws IOException { List files = showFiles(directory, true); final List causeList = new ArrayList<>(); for (final File file : files) { try { forceDelete(file); } catch (final IOException ioe) { causeList.add(ioe); } } if (!causeList.isEmpty()) { throw new IOExceptionList(directory.toString(), causeList); } } public static void forceDelete(final File file) throws IOException { Objects.requireNonNull(file, "file"); final Counters.PathCounters deleteCounters; try { deleteCounters = PathUtils.delete(file.toPath(), PathUtils.EMPTY_LINK_OPTION_ARRAY, StandardDeleteOption.OVERRIDE_READ_ONLY); } catch (final IOException e) { throw new IOException("Cannot delete file: " + file, e); } if (deleteCounters.getFileCounter().get() < 1 && deleteCounters.getDirectoryCounter().get() < 1) { // didn't find a file to delete. throw new FileNotFoundException("File does not exist: " + file); } } public static void iterateLines(File file, Consumer lineConsumer) throws IOException { //创建类进行文件的读取,并指定编码格式为utf-8 InputStreamReader read = new InputStreamReader(Files.newInputStream(file.toPath()), StandardCharsets.UTF_8); BufferedReader in = new BufferedReader(read);//可用于读取指定文件 String line = null; while ((line = in.readLine()) != null) { lineConsumer.accept(line); } in.close(); } /** * 文件是否空白 = not exists / blank * @param fileAbsolutePath 目标文件全路径 * @return isBlank */ public static boolean isFileBlank(String fileAbsolutePath) { File file = new File(fileAbsolutePath); if (!file.exists()) { return true; } if (file.length() == 0) { return true; } return false; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy