
com.github.houbb.heaven.util.io.FileUtil Maven / Gradle / Ivy
Show all versions of heaven Show documentation
/*
* Copyright (c) 2019. houbinbin Inc.
* heaven All rights reserved.
*/
package com.github.houbb.heaven.util.io;
import com.github.houbb.heaven.constant.CharsetConst;
import com.github.houbb.heaven.constant.FileTypeConst;
import com.github.houbb.heaven.response.exception.CommonRuntimeException;
import com.github.houbb.heaven.support.handler.IMapHandler;
import com.github.houbb.heaven.util.common.ArgUtil;
import com.github.houbb.heaven.util.io.filewalker.AllFileVisitor;
import com.github.houbb.heaven.util.lang.StringUtil;
import com.github.houbb.heaven.util.util.ArrayUtil;
import com.github.houbb.heaven.util.util.MapUtil;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.file.*;
import java.util.*;
/**
* 文件工具类
* 1. 用于获取文件的内容
*
* @author bbhou
* @since 0.0.1
*/
public final class FileUtil {
private FileUtil() {
}
/**
* 获取文件内容
*
* @param filePath 文件路径
* @return 文件不存在或异常等, 直接抛出异常
* @since 0.1.80
*/
public static String getFileContent(String filePath) {
return getFileContent(filePath, CharsetConst.UTF8);
}
/**
* 获取文件内容
*
* @param filePath 文件路径
* @param charset 文件编码
* @return 文件不存在或异常等, 直接抛出异常
* @since 0.1.80
*/
public static String getFileContent(String filePath, final String charset) {
File file = new File(filePath);
if (file.exists()) {
try (InputStream inputStream = new FileInputStream(file)) {
return getFileContent(inputStream, charset);
} catch (IOException e) {
throw new CommonRuntimeException(e);
}
}
throw new CommonRuntimeException(filePath + " is not exists!");
}
/**
* 获取文件内容
* 默认编码UTF8
*
* @param inputStream 输入流
* @return 文件内容
* @since 0.1.10
*/
public static String getFileContent(InputStream inputStream) {
return getFileContent(inputStream, CharsetConst.UTF8);
}
/**
* 获取文件内容
* 默认编码UTF8
*
* @param file 文件
* @param charset 文件编码
* @return 文件内容
* @since 0.1.94
*/
public static String getFileContent(final File file,
final String charset) {
try (InputStream inputStream = new FileInputStream(file)) {
return getFileContent(inputStream, charset);
} catch (IOException e) {
throw new CommonRuntimeException(e);
}
}
/**
* 获取文件内容
* 默认编码UTF8
*
* @param file 文件
* @return 文件内容
* @since 0.1.94
*/
public static String getFileContent(final File file) {
try (InputStream inputStream = new FileInputStream(file)) {
return getFileContent(inputStream);
} catch (IOException e) {
throw new CommonRuntimeException(e);
}
}
/**
* 获取文件内容
*
* @param inputStream 文件输入流
* @param charset 文件编码
* @return 文件内容字符串
* @since 0.1.10
*/
public static String getFileContent(InputStream inputStream, String charset) {
Charset charsetVal = Charset.forName(charset);
return getFileContent(inputStream, 0, Integer.MAX_VALUE, charsetVal);
}
/**
* 获取文件内容
*
* @param inputStream 输入流
* @param startIndex 开始下标
* @param endIndex 结束下标
* @param charset 编码
* @return 结果
* @since 0.1.85
*/
public static String getFileContent(final InputStream inputStream,
int startIndex,
int endIndex,
final Charset charset) {
try {
// 参数纠正
endIndex = Math.min(endIndex, inputStream.available());
startIndex = Math.max(0, startIndex);
// 跳过指定长度
inputStream.skip(startIndex);
// 这个读取的数据可能不正确
// InputStream.read(byte[] b) 无法保证读取的结果正确。
final int count = endIndex - startIndex;
byte[] bytes = new byte[count];
// 已经成功读取的字节的个数
// -1 也代表结束
int readCount = 0;
while (readCount < count && readCount != -1) {
readCount += inputStream.read(bytes, readCount, count - readCount);
}
return new String(bytes, charset);
} catch (IOException e) {
throw new CommonRuntimeException(e);
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 获取文件后缀
*
* @param fileName 文件名称
* @return 文件后缀
*/
public static String getSuffix(String fileName) {
return fileName.substring(fileName.lastIndexOf('.') + 1);
}
/**
* 获取指定路径文件的每一行内容
*
* @param filePath 文件路径
* @param initLine 初始化行数
* @return 内容列表
*/
public static List getFileContentEachLine(String filePath, int initLine) {
File file = new File(filePath);
return getFileContentEachLine(file, initLine);
}
/**
* 获取指定路径文件的每一行内容
* 1.初始化行数默认为0
*
* @param filePath 文件路径
* @return 内容列表
* @see #getFileContentEachLine(String, int) 获取指定路径文件的每一行内容
*/
public static List getFileContentEachLine(String filePath) {
File file = new File(filePath);
return getFileContentEachLine(file, 0);
}
/**
* 获取指定文件的每一行内容。并对内容进行trim()操作。
*
* @param filePath 文件路径
* @param initLine 初始化行数
* @return 内容列表
*/
public static List getFileContentEachLineTrim(String filePath, int initLine) {
List stringList = getFileContentEachLine(filePath, initLine);
List resultList = new LinkedList<>();
for (String string : stringList) {
resultList.add(string.trim());
}
return resultList;
}
/**
* 获取指定文件的每一行内容
* 默认初始行数为0
*
* @param file 文件
* @return 内容列表
*/
public static List getFileContentEachLine(File file) {
return getFileContentEachLine(file, 0);
}
/**
* 获取指定文件的每一行内容
* [TWR](http://blog.csdn.net/doctor_who2004/article/details/50901195)
*
* @param file 指定读取文件
* @param initLine 初始读取行数
* @return 错误返回空列表
* @since 1.7
*/
public static List getFileContentEachLine(File file, int initLine) {
List contentList = new LinkedList<>();
if (!file.exists()) {
return contentList;
}
//暂时使用此编码
String charset = "UTF-8";
try (FileInputStream fileInputStream = new FileInputStream(file);
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, charset);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader)
) {
// 用于记录行号
int lineNo = 0;
while (lineNo < initLine) {
lineNo++;
String ignore = bufferedReader.readLine();
}
String dataEachLine; //每一行的内容
while ((dataEachLine = bufferedReader.readLine()) != null) {
lineNo++;
//跳过空白行
if (Objects.equals("", dataEachLine)) {
continue;
}
contentList.add(dataEachLine);
}
} catch (IOException e) {
throw new CommonRuntimeException(e);
}
return contentList;
}
/**
* 获取文件内容的列表
*
* @param file 文件
* @param initLine 0 开始
* @param endLine 下标从0开始
* @param charset 编码
* @return string list
*/
@Deprecated
public static List getFileContentEachLine(final File file, final int initLine, final int endLine, final String charset) {
List contentList = new LinkedList<>();
if (!file.exists()) {
return contentList;
}
try (FileInputStream fileInputStream = new FileInputStream(file);
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, charset);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader)
) {
// 用于记录行号
int lineNo = 0;
while (lineNo < initLine) {
lineNo++;
String ignore = bufferedReader.readLine();
}
//每一行的内容
String dataEachLine;
while ((dataEachLine = bufferedReader.readLine()) != null
&& lineNo < endLine) {
lineNo++;
contentList.add(dataEachLine);
}
} catch (IOException e) {
throw new CommonRuntimeException(e);
}
return contentList;
}
/**
* 获取每一行的文件内容
* (1)如果文件不存在,直接返回空列表。
*
* @param file 文件信息
* @param charset 编码
* @param initLine 初始化行
* @param endLine 结束航
* @param ignoreEmpty 是否跳过空白行
* @return 结果列表
* @since 0.1.65
*/
public static List readAllLines(final File file,
final String charset,
final int initLine,
final int endLine,
final boolean ignoreEmpty) {
ArgUtil.notNull(file, "file");
ArgUtil.notEmpty(charset, "charset");
if (!file.exists()) {
throw new CommonRuntimeException("File not exists!");
}
try (FileInputStream inputStream = new FileInputStream(file)) {
return readAllLines(inputStream, charset, initLine, endLine, ignoreEmpty);
} catch (IOException e) {
throw new CommonRuntimeException(e);
}
}
/**
* 获取每一行的文件内容
* (1)如果文件不存在,直接返回空列表。
*
* @param inputStream 文件输入流
* @param charset 编码
* @param initLine 初始化行
* @param endLine 结束航
* @param ignoreEmpty 是否跳过空白行
* @return 结果列表
* @since 0.1.95
*/
public static List readAllLines(final InputStream inputStream,
final String charset,
final int initLine,
final int endLine,
final boolean ignoreEmpty) {
ArgUtil.notNull(inputStream, "inputStream");
ArgUtil.notEmpty(charset, "charset");
List contentList = new LinkedList<>();
try (InputStreamReader inputStreamReader = new InputStreamReader(inputStream, charset);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader)
) {
// 用于记录行号
int lineNo = 0;
while (lineNo < initLine) {
lineNo++;
String ignore = bufferedReader.readLine();
}
//每一行的内容
String dataEachLine;
while ((dataEachLine = bufferedReader.readLine()) != null
&& lineNo < endLine) {
lineNo++;
// 跳过空白行且内容为空,则不进行计入结果
if (ignoreEmpty && StringUtil.isEmpty(dataEachLine)) {
// ignore
continue;
} else {
contentList.add(dataEachLine);
}
}
} catch (IOException e) {
throw new CommonRuntimeException(e);
} finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return contentList;
}
/**
* 获取每一行的文件内容
* (1)如果文件不存在,直接返回空列表。
*
* @param inputStream 文件输入流
* @param charset 编码
* @param initLine 初始化行
* @param endLine 结束航
* @return 结果列表
* @since 0.1.95
*/
public static List readAllLines(final InputStream inputStream,
final String charset,
final int initLine,
final int endLine) {
return readAllLines(inputStream, charset, initLine, endLine, true);
}
/**
* 获取每一行的文件内容
* (1)如果文件不存在,直接返回空列表。
*
* @param inputStream 文件输入流
* @param charset 编码
* @param initLine 初始化行
* @return 结果列表
* @since 0.1.95
*/
public static List readAllLines(final InputStream inputStream,
final String charset,
final int initLine) {
return readAllLines(inputStream, charset, initLine, Integer.MAX_VALUE);
}
/**
* 获取每一行的文件内容
* (1)如果文件不存在,直接返回空列表。
*
* @param inputStream 文件输入流
* @param charset 编码
* @return 结果列表
* @since 0.1.95
*/
public static List readAllLines(final InputStream inputStream,
final String charset) {
return readAllLines(inputStream, charset, 0);
}
/**
* 获取每一行的文件内容
* (1)如果文件不存在,直接返回空列表。
*
* @param inputStream 文件输入流
* @return 结果列表
* @since 0.1.95
*/
public static List readAllLines(final InputStream inputStream) {
return readAllLines(inputStream, CharsetConst.UTF8);
}
/**
* 获取每一行的文件内容
*
* @param filePath 文件路径
* @param charset 文件编码
* @param ignoreEmpty 是否跳过空白行
* @return 结果列表
* @since 0.1.65
*/
public static List readAllLines(final String filePath,
final String charset,
final boolean ignoreEmpty) {
File file = new File(filePath);
return readAllLines(file, charset, 0, Integer.MAX_VALUE, ignoreEmpty);
}
/**
* 获取每一行的文件内容
*
* @param file 文件路径
* @param charset 文件编码
* @param ignoreEmpty 是否跳过空白行
* @return 结果列表
* @since 0.1.88
*/
public static List readAllLines(final File file,
final String charset,
final boolean ignoreEmpty) {
return readAllLines(file, charset, 0, Integer.MAX_VALUE, ignoreEmpty);
}
/**
* 获取每一行的文件内容
*
* @param file 文件路径
* @param charset 文件编码
* @return 结果列表
* @since 0.1.88
*/
public static List readAllLines(final File file,
final String charset) {
return readAllLines(file, charset, false);
}
/**
* 获取每一行的文件内容
*
* @param file 文件路径
* @return 结果列表
* @since 0.1.88
*/
public static List readAllLines(final File file) {
return readAllLines(file, CharsetConst.UTF8);
}
/**
* 获取每一行的文件内容
*
* @param filePath 文件路径
* @param charset 文件编码
* @return 结果列表
* @since 0.1.65
*/
public static List readAllLines(final String filePath,
final String charset) {
return readAllLines(filePath, charset, false);
}
/**
* 获取每一行的文件内容
*
* @param filePath 文件路径
* @return 结果列表
* @since 0.1.65
*/
public static List readAllLines(final String filePath) {
return readAllLines(filePath, CharsetConst.UTF8);
}
/**
* 复制文件夹
*
* @param sourceDir 原始文件夹
* @param targetDir 目标文件夹
* @throws IOException if any
* @since 1.1.2
*/
public static void copyDir(String sourceDir, String targetDir) throws IOException {
File file = new File(sourceDir);
String[] filePath = file.list();
if (!(new File(targetDir)).exists()) {
(new File(targetDir)).mkdir();
}
if (ArrayUtil.isNotEmpty(filePath)) {
for (String aFilePath : filePath) {
if ((new File(sourceDir + File.separator + aFilePath)).isDirectory()) {
copyDir(sourceDir + File.separator + aFilePath, targetDir + File.separator + aFilePath);
}
if (new File(sourceDir + File.separator + aFilePath).isFile()) {
copyFile(sourceDir + File.separator + aFilePath, targetDir + File.separator + aFilePath);
}
}
}
}
/**
* 复制文件
*
* @param sourceFile 原始路径
* @param targetPath 目标路径
* @throws IOException if any
* @since 1.1.2
*/
public static void copyFile(String sourceFile, String targetPath) throws IOException {
File oldFile = new File(sourceFile);
File file = new File(targetPath);
try (FileInputStream in = new FileInputStream(oldFile);
FileOutputStream out = new FileOutputStream(file)) {
byte[] buffer = new byte[2097152];
while ((in.read(buffer)) != -1) {
out.write(buffer);
}
}
}
/**
* 写入文件信息
* (1)默认 utf-8 编码
* (2)默认新建一个文件
* (3)默认为一行
*
* @param filePath 文件路径
* @param line 行信息
* @param openOptions 操作属性
* @since 0.1.78
*/
public static void write(final String filePath, final CharSequence line, OpenOption... openOptions) {
write(filePath, Collections.singletonList(line), openOptions);
}
/**
* 写入文件信息
* (1)默认 utf-8 编码
* (2)默认新建一个文件
*
* @param filePath 文件路径
* @param lines 行信息
* @param openOptions 文件选项
* @since 0.1.22
*/
public static void write(final String filePath, final Iterable extends CharSequence> lines, OpenOption... openOptions) {
write(filePath, lines, CharsetConst.UTF8, openOptions);
}
/**
* 写入文件信息
*
* @param filePath 文件路径
* @param lines 行信息
* @param charset 文件编码
* @param openOptions 文件操作选项
* @since 0.1.22
*/
public static void write(final String filePath, final Iterable extends CharSequence> lines,
final String charset, OpenOption... openOptions) {
try {
// ensure lines is not null before opening file
ArgUtil.notNull(lines, "charSequences");
CharsetEncoder encoder = Charset.forName(charset).newEncoder();
final Path path = Paths.get(filePath);
// 创建父类文件夹
Path pathParent = path.getParent();
// 路径判断空
if(pathParent != null) {
File parent = pathParent.toFile();
if (!parent.exists()) {
parent.mkdirs();
}
}
OutputStream out = path.getFileSystem().provider().newOutputStream(path, openOptions);
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, encoder))) {
for (CharSequence line : lines) {
writer.append(line);
writer.newLine();
}
}
} catch (IOException e) {
throw new CommonRuntimeException(e);
}
}
/**
* 创建文件
* (1)文件路径为空,则直接返回 false
* (2)如果文件已经存在,则返回 true
* (3)如果文件不存在,则创建文件夹,然后创建文件。
* 3.1 如果父类文件夹创建失败,则直接返回 false.
*
* @param filePath 文件路径
* @return 是否成功
* @throws CommonRuntimeException 运行时异常,如果创建文件异常。包括的异常为 {@link IOException} 文件异常.
* @since 0.1.24
*/
public static boolean createFile(final String filePath) {
if (StringUtil.isEmpty(filePath)) {
return false;
}
if (FileUtil.exists(filePath)) {
return true;
}
File file = new File(filePath);
// 父类文件夹的处理
File dir = file.getParentFile();
if (dir != null && FileUtil.notExists(dir)) {
boolean mkdirResult = dir.mkdirs();
if (!mkdirResult) {
return false;
}
}
// 创建文件
try {
return file.createNewFile();
} catch (IOException e) {
throw new CommonRuntimeException(e);
}
}
/**
* 文件是否存在
*
* @param filePath 文件路径
* @param options 连接选项
* @return 是否存在
* @since 0.1.24
*/
public static boolean exists(final String filePath, LinkOption... options) {
if (StringUtil.isEmpty(filePath)) {
return false;
}
Path path = Paths.get(filePath);
return Files.exists(path, options);
}
/**
* 文件是否不存在
*
* @param filePath 文件路径
* @param options 连接选项
* @return 是否存在
* @since 0.1.24
*/
public static boolean notExists(final String filePath, LinkOption... options) {
return !exists(filePath, options);
}
/**
* 文件是否不存在
*
* @param file 文件
* @return 是否存在
* @since 0.1.24
*/
public static boolean notExists(final File file) {
ArgUtil.notNull(file, "file");
return !file.exists();
}
/**
* 判断文件是否为空
* (1)文件不存在,返回 true
* (2)文件存在,且 {@link File#length()} 为0,则认为空。
* (3)文件存在,且length大于0,则认为不空
*
* @param filePath 文件路径
* @return 内容是否为空
* @since 0.1.24
*/
public static boolean isEmpty(final String filePath) {
if (StringUtil.isEmpty(filePath)) {
return true;
}
File file = new File(filePath);
return file.length() <= 0;
}
/**
* 内容是否为不空
*
* @param filePath 文件路径
* @return 内容是否为不空
* @since 0.1.24
*/
public static boolean isNotEmpty(final String filePath) {
return !isEmpty(filePath);
}
/**
* 获取文件字节数组
*
* @param file 文件信息
* @return 字节数组
* @since 0.1.50
*/
public static byte[] getFileBytes(final File file) {
ArgUtil.notNull(file, "file");
try (FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream(1024)) {
byte[] b = new byte[1024];
int n;
while ((n = fis.read(b)) != -1) {
bos.write(b, 0, n);
}
return bos.toByteArray();
} catch (IOException e) {
throw new CommonRuntimeException(e);
}
}
/**
* 获取文件字节流
*
* @param filePath 文件路径
* @return 字节数组
* @since 0.1.50
*/
public static byte[] getFileBytes(final String filePath) {
ArgUtil.notNull(filePath, "filePath");
File file = new File(filePath);
return getFileBytes(file);
}
/**
* 根据字节信息创建文件
*
* @param filePath 文件路径
* @param bytes 字节数组
* @see #createFileAssertSuccess 断言创建成功
* @since 0.1.50
*/
public static void createFile(final String filePath, final byte[] bytes) {
File file = createFileAssertSuccess(filePath);
try (FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);) {
bos.write(bytes);
} catch (Exception e) {
throw new CommonRuntimeException(e);
}
}
/**
* 创建文件
*
* @param filePath 文件路径
* @return 文件信息
* @throws CommonRuntimeException 运行时异常,如果创建文件异常。包括的异常为 {@link IOException} 文件异常.
* @since 0.1.50
*/
public static File createFileAssertSuccess(final String filePath) {
ArgUtil.notEmpty(filePath, "filePath");
// 判断文件是否存在
File file = new File(filePath);
if (file.exists()) {
return file;
}
// 父类文件夹的处理
File dir = file.getParentFile();
if (FileUtil.notExists(dir)) {
boolean mkdirResult = dir.mkdirs();
if (!mkdirResult) {
throw new CommonRuntimeException("Parent file create fail " + filePath);
}
}
try {
// 创建文件
boolean createFile = file.createNewFile();
if (!createFile) {
throw new CommonRuntimeException("Create new file fail for path " + filePath);
}
return file;
} catch (IOException e) {
throw new CommonRuntimeException(e);
}
}
/**
* 删除文件
*
* @param file 文件信息
* @since 0.1.50
*/
public static void deleteFile(final File file) {
ArgUtil.notNull(file, "file");
if (file.exists()) {
boolean result = file.delete();
if (!result) {
throw new CommonRuntimeException("Delete file fail for path " + file.getAbsolutePath());
}
}
}
/**
* 删除文件
*
* @param filePath 文件信息
* @since 0.1.141
*/
public static void deleteFile(final String filePath) {
ArgUtil.notEmpty(filePath, "filePath");
File file = new File(filePath);
deleteFile(file);
}
/**
* 递归删除文件(包含子文件+文件夹)
*
* @param filePath 文件信息
* @since 0.8.0
*/
public static void deleteFileRecursive(final String filePath) {
ArgUtil.notEmpty(filePath, "filePath");
File dir = new File(filePath);
File[] list = dir.listFiles(); //无法做到list多层文件夹数据
if (list != null) {
for (File temp : list) { //先去递归删除子文件夹及子文件
deleteFileRecursive(temp.getAbsolutePath()); //注意这里是递归调用
}
}
//再删除自己本身的文件夹
dir.delete();
}
/**
* 递归删除文件(包含子文件+文件夹)
*
* @param file 文件信息
* @since 0.8.0
*/
public static void deleteFileRecursive(final File file) {
ArgUtil.notNull(file, "file");
deleteFileRecursive(file.getAbsolutePath());
}
/**
* 创建临时文件
*
* @param name 文件名称
* @param suffix 文件后缀
* @return 临时文件
* @since 0.1.50
*/
public static File createTempFile(final String name, final String suffix) {
try {
ArgUtil.notEmpty(name, "prefix");
ArgUtil.notEmpty(suffix, "suffix");
return File.createTempFile(name, suffix);
} catch (IOException e) {
throw new CommonRuntimeException(e);
}
}
/**
* 创建临时文件
*
* @param nameWithSuffix 文件名称全称
* @return 临时文件
* @since 0.1.50
*/
public static File createTempFile(final String nameWithSuffix) {
try {
ArgUtil.notEmpty(nameWithSuffix, "fileName");
String[] strings = nameWithSuffix.split("\\.");
return File.createTempFile(strings[0], strings[1]);
} catch (IOException e) {
throw new CommonRuntimeException(e);
}
}
/**
* 是否为图片格式
*
* @param string 原始字符串
* @return 是否为图片
* @since 0.1.73
*/
public static boolean isImage(final String string) {
if (StringUtil.isEmpty(string)) {
return false;
}
return string.endsWith(FileTypeConst.Image.PNG)
|| string.endsWith(FileTypeConst.Image.JPEG)
|| string.endsWith(FileTypeConst.Image.JPG)
|| string.endsWith(FileTypeConst.Image.GIF);
}
/**
* 将文件内容转换为 map
*
* @param inputStream 输入流
* @param charset 文件编码
* @param mapHandler 转换实现
* @param key 泛型
* @param value 泛型
* @return 结果
* @since 0.1.95
*/
public static Map readToMap(final InputStream inputStream,
final String charset,
final IMapHandler mapHandler) {
List allLines = FileUtil.readAllLines(inputStream, charset);
return MapUtil.toMap(allLines, mapHandler);
}
/**
* 将文件内容转换为 map
*
* @param path 文件路径
* @param charset 文件编码
* @param mapHandler 转换实现
* @param key 泛型
* @param value 泛型
* @return 结果
* @since 0.1.83
*/
public static Map readToMap(final String path,
final String charset,
final IMapHandler mapHandler) {
List allLines = FileUtil.readAllLines(path, charset);
return MapUtil.toMap(allLines, mapHandler);
}
/**
* 将文件内容转换为 map
*
* @param path 文件路径
* @param mapHandler 转换实现
* @param key 泛型
* @param value 泛型
* @return 结果
* @since 0.1.83
*/
public static Map readToMap(final String path,
final IMapHandler mapHandler) {
return readToMap(path, CharsetConst.UTF8, mapHandler);
}
/**
* 将文件内容转换为 map
*
* (1)直接拆分。取第一个值和第一个值
* (2)默认使用空格分隔
* @param path 文件路径
* @return 结果
* @since 0.1.119
*/
public static Map readToMap(final String path) {
return readToMap(path, " ");
}
/**
* 将文件内容转换为 map
*
* (1)直接拆分。取第一个值和第一个值
*
* @param path 文件路径
* @param splitter 分隔符号
* @return 结果
* @since 0.1.83
*/
public static Map readToMap(final String path,
final String splitter) {
return readToMap(path, new IMapHandler() {
@Override
public String getKey(String o) {
return o.split(splitter)[0];
}
@Override
public String getValue(String o) {
return o.split(splitter)[1];
}
});
}
/**
* 获取文件名称
*
* @param path 完整路径
* @return 名称
* @since 0.1.86
*/
public static String getFileName(final String path) {
if (StringUtil.isEmptyTrim(path)) {
return StringUtil.EMPTY;
}
File file = new File(path);
String name = file.getName();
return name.substring(0, name.lastIndexOf('.'));
}
/**
* 获取父类路径
*
* @param path 当前路径
* @return 父类路径
* @since 0.1.86
*/
public static String getDirPath(final String path) {
Path path1 = Paths.get(path);
return path1.getParent().toAbsolutePath().toString() + File.separator;
}
/**
* 移除 windows 中禁止出现的特殊符号名称
*
* @param name 名称
* @return 结果
* @since 0.1.88
*/
public static String trimWindowsSpecialChars(final String name) {
if (StringUtil.isEmpty(name)) {
return name;
}
return name.replaceAll("[?/\\\\*<>|:\"]", "");
}
/**
* 重命名
*
* @param sourcePath 原始路径
* @param targetPath 结果路径
* @return 重命名结果
* @since 0.1.98
*/
public static boolean rename(final String sourcePath,
final String targetPath) {
File sourceFile = new File(sourcePath);
File targetFile = new File(targetPath);
return sourceFile.renameTo(targetFile);
}
/**
* 文件合并
*
* @param result 结果路径
* @param sources 其他待合并文件路径
* @since 0.1.99
*/
public static void merge(final String result,
final String... sources) {
ArgUtil.notEmpty(result, "result");
ArgUtil.notEmpty(sources, "sources");
try (OutputStream os = new FileOutputStream(result)) {
for (String source : sources) {
byte[] bytes = getFileBytes(source);
os.write(bytes);
}
} catch (IOException e) {
throw new CommonRuntimeException(e);
}
}
/**
* 将指定的数组信息合并到指定的文件中
*
* @param result 结果路径
* @param byteArrays 其他待合并文件路径
* @since 0.1.99
*/
public static void merge(final String result,
final byte[]... byteArrays) {
ArgUtil.notEmpty(result, "result");
ArgUtil.notEmpty(byteArrays, "byteArrays");
try (OutputStream os = new FileOutputStream(result)) {
for (byte[] bytes : byteArrays) {
os.write(bytes);
}
} catch (IOException e) {
throw new CommonRuntimeException(e);
}
}
/**
* 将指定的数组信息合并到指定的文件中
*
* @param result 结果路径
* @param byteArrayList 其他待合并文件字节数组
* @since 0.1.99
*/
public static void merge(final String result,
final List byteArrayList) {
ArgUtil.notEmpty(result, "result");
ArgUtil.notEmpty(byteArrayList, "byteArrayList");
try (OutputStream os = new FileOutputStream(result)) {
for (byte[] bytes : byteArrayList) {
os.write(bytes);
}
} catch (IOException e) {
throw new CommonRuntimeException(e);
}
}
/**
* 写入字节到文件
*
* @param filePath 文件路径
* @param bytes 字节信息
* @since 0.2.1
*/
public static void write(final String filePath,
final byte[] bytes) {
ArgUtil.notEmpty(filePath, "filePath");
try (OutputStream os = new FileOutputStream(filePath)) {
os.write(bytes);
} catch (IOException e) {
throw new CommonRuntimeException(e);
}
}
/**
* 转义 windows 下的特殊字符
* @param fileName 文件名称
* @return 转义后的字符串
* @since 0.1.113
*/
public static String escapeWindowsSpecial(final String fileName) {
if(StringUtil.isEmpty(fileName)) {
return fileName;
}
return fileName.replaceAll("[\"<>/\\\\|:*?]", "");
}
/**
* 创建文件夹
* @param dir 文件夹
* @return 结果
* @since 0.1.113
*/
public static boolean createDir(final String dir) {
if(StringUtil.isEmpty(dir)) {
return false;
}
File file = new File(dir);
if (file.isDirectory()) {
return file.mkdirs();
}
return false;
}
/**
* 清空文件内容
* @param filePath 文件路径
* @since 0.1.116
*/
public static void truncate(final String filePath) {
FileUtil.write(filePath, StringUtil.EMPTY, StandardOpenOption.TRUNCATE_EXISTING);
}
/**
* 追加文件内容
* @param filePath 文件路径
* @param line 文件内容
* @since 0.1.117
*/
public static void append(final String filePath, final String line) {
FileUtil.write(filePath, line, StandardOpenOption.APPEND);
}
/**
* 追加文件内容
* @param filePath 文件路径
* @param collection 文件内容
* @since 0.1.117
*/
public static void append(final String filePath, final Collection collection) {
FileUtil.write(filePath, collection, StandardOpenOption.APPEND);
}
/**
* 将文件转成 base64 字符串
*
* https://www.cnblogs.com/darkhumor/p/7525392.html
* https://blog.csdn.net/phoenix_cat/article/details/84676302
* https://blog.csdn.net/myloverisxin/article/details/117530365
* https://www.cnblogs.com/yejg1212/p/11926649.html
*
* 不同规范编码不同,会导致出现换行符号,但是解码的时候会被忽略。
* @param filePath 文件路径
* @return base64 字符串
* @since 0.1.146
*/
public static String fileToBase64(String filePath) {
File file = new File(filePath);
try(FileInputStream inputFile = new FileInputStream(file)) {
byte[] buffer = new byte[(int)file.length()];
inputFile.read(buffer);
String plainText = Base64.getEncoder().encodeToString(buffer);
return plainText.replaceAll("\r", "")
.replaceAll("\n", "");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 将base64字符解码保存文件
* @param base64Code base64 内容
* @param targetPath 目标文件
* @since 0.1.146
*/
public static void base64ToFile(String base64Code,String targetPath) {
FileUtil.createFile(targetPath);
// base64 前端传过来,可能会有前缀 xxx,
if(base64Code.contains(",")) {
base64Code = base64Code.split(",")[1];
}
try(FileOutputStream out = new FileOutputStream(targetPath);) {
byte[] buffer = Base64.getDecoder().decode(base64Code);
out.write(buffer);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 获取对应的文件流 reader
*
* @param sourceFilePath 原始文件
* @return 结果
* @since 0.1.164
*/
public static BufferedReader getBufferedReader(String sourceFilePath) {
try {
ArgUtil.notEmpty(sourceFilePath, "sourceFilePath");
Path path = Paths.get(sourceFilePath);
InputStream inputStream = Files.newInputStream(path);
InputStreamReader streamReader = new InputStreamReader(inputStream);
return new BufferedReader(streamReader);
// new BufferedReader(new FileReader(sourceFilePath))
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 关闭流
* @param bufferedReader 流
* @since 0.1.164
*/
public static void closeBufferReader(BufferedReader bufferedReader) {
if(bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
/**
* 文件路径
* @param filePath 文件
* @return 结果
* @since 0.1.164
*/
public static BufferedWriter getBufferedWriter(final String filePath) {
try {
ArgUtil.notEmpty(filePath, "filePath");
return new BufferedWriter(new FileWriter(filePath));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 关闭流
* @param bufferedWriter 流
* @since 0.1.164
*/
public static void closeBufferedWriter(BufferedWriter bufferedWriter) {
if(bufferedWriter != null) {
try {
bufferedWriter.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
/**
* 排序后的文件内容去重
*
* 说明:针对无法内存一次加载的大文件,原始文件必须已经排序。
* @param sourceFile 原始文件
* @param targetFile 目标文件
* @since 0.1.164
*/
public static void sortedUnique(final String sourceFile,
final String targetFile) {
String prefixLine = null;
try(BufferedReader sourceReader = getBufferedReader(sourceFile);
BufferedWriter resultWriter = getBufferedWriter(targetFile);) {
String sourceLine = sourceReader.readLine();
// 这里暂时不考虑重复行的问题(可以文件先去重复)
// 只能比较出左边在右边没有的,右边和左边的差异需要反过来对比一次。
while (sourceLine != null) {
// 和上一行对比
if(!sourceLine.equals(prefixLine)) {
resultWriter.write(sourceLine);
resultWriter.newLine();
}
prefixLine = sourceLine;
sourceLine = sourceReader.readLine();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 是否为 md 文件
* @param filePath 文件路径
* @return {@code true} 是
*/
public static boolean isMdFile(final String filePath) {
if(StringUtil.isEmpty(filePath)) {
return false;
}
return filePath.endsWith(".md")
|| filePath.endsWith(".markdown");
}
/**
* md 文件对应的列表
*
* @param dirPath 文件夹路径
* @param subTree 包含子元素
* @return 对应的列表
*/
public static List getMdFilePathList(final Path dirPath,
final boolean subTree) {
try {
if(subTree) {
MarkdownFileWalker markdownFileWalker = new MarkdownFileWalker();
Files.walkFileTree(dirPath, markdownFileWalker);
return markdownFileWalker.getPathList();
}
File dir = dirPath.toFile();
File[] files = dir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return FileUtil.isMdFile(name);
}
});
if(ArrayUtil.isNotEmpty(files)) {
List paths = new ArrayList<>();
for(File file : files) {
paths.add(file.toPath());
}
return paths;
}
return Collections.emptyList();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 获取所有的文件列表,包含递归
* @param dir 文件夹
* @return 结果
* @since 0.2.2
*/
public static List getAllFilePathList(String dir) {
try {
AllFileVisitor allFileVisitor = new AllFileVisitor();
Files.walkFileTree(Paths.get(dir), allFileVisitor);
return allFileVisitor.getPathList();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 获取所有的文件列表
* @param dir 文件夹
* @param fileList 文件列表
* @since 0.2.2
*/
public static void getAllFileList(File dir, List fileList) {
if(dir.isDirectory()) {
File[] files = dir.listFiles();
if(ArrayUtil.isNotEmpty(files)) {
for(File childFile : files) {
// 递归
getAllFileList(childFile, fileList);
}
}
} else {
// 文件
fileList.add(dir);
}
}
/**
* 构建完整的路径。
* 给定一个前缀和路径,此方法将两者结合形成一个完整的URL或文件路径。
* 如果前缀末尾没有斜杠,则会在两者之间添加一个斜杠,确保路径的正确拼接。
*
* @param prefix 路径前缀。例如,http://example.com或C:\Users。
* @param path 相对路径。例如,path/to/resource或test.txt。
* @return 拼接后的完整路径。确保路径正确连接,不会因缺少斜杠而导致路径错误。
* @since 0.10.0
*/
public static String buildFullPath(String prefix, String path) {
// 检查前缀是否已以斜杠结尾,如果是,则直接拼接路径;如果不是,则在前缀后添加斜杠再拼接路径
if(path.startsWith("/")) {
path = path.substring(1);
}
if(prefix.endsWith("/")) {
return prefix + path;
} else {
return prefix + "/" + path;
}
}
public static void main(String[] args) {
System.out.println(FileUtil.fileToBase64("C:\\Users\\dh\\Pictures\\Screenshots\\config.png"));
}
}