package api.common.util; import lombok.SneakyThrows; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; import org.springframework.util.ResourceUtils; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.util.*; public class FileUtil { /** * 获取所有同一类型的文件列表。 * * @param rootPath 文件 File 路径。 * @param suffix 文件后缀类型。 */ @SneakyThrows public static List listAbsolutePathByFiletype(String rootPath, String suffix) { List result = new LinkedList<>(); File rootFile = new File(rootPath); //1 判断文件是否存在 if (!rootFile.exists()) { throw new RuntimeException("FileUtil--listAbsolutePathByFiletype 文件 " + rootPath + " 不存在!"); } //2 判断是否是文件 if (rootFile.isFile() && rootFile.getName().equals(suffix)) { return new ArrayList<>(Collections.singletonList(rootPath)); } //3 判断是否是目录 if (rootFile.isDirectory()) { File[] children = rootFile.listFiles(); if (children != null) { for (File child : children) { result.addAll(listAbsolutePathByFiletype(child.getAbsolutePath(), suffix)); } } } return result; } /** * 获取当前目录下的一级文件全路径列表 * @param path 根路径 * @return 文件全路径列表 */ public static List ls(String path) { File[] files = new File(path).listFiles(); if (files == null){ throw new RuntimeException("路径不存在!"); } List result = new ArrayList<>(); for (File file : files) { result.add(file.getAbsolutePath()) ; } return result; } @SneakyThrows public static String read(String path){ return read(getFile(path)); } public static String cat(String path) throws Exception { return read(getFile(path)); } public static String read(File file) throws IOException { return read(new FileInputStream(file)); } public static String read(InputStream inputStream) throws IOException { StringBuilder result = new StringBuilder(); byte[] buf = new byte[4096];//创建字节数组,存储临时读取的数据 int len;//记录数据读取的长度 //循环读取数据 while ((len = inputStream.read(buf)) != -1) { //长度为-1则读取完毕 result.append(new String(buf, 0, len)).append("\n"); } inputStream.close(); return result.toString(); } // -------------------------------- A -------------------------------- /** * 添加文件后缀 * * @param url 路径 * @return 有后缀名的文件 */ public static String addSeparator(String url) { if (File.separator.equals(url.charAt(url.length() - 1) + "")) { return url; } return url + File.separator; } /** * 添加文件后缀 * * @param ambiguousFileName 不确定是否有后缀的文件名 * @return 有后缀名的文件 */ public static String addSuffix(String ambiguousFileName, String suffix) { if (ambiguousFileName == null || "".equals(ambiguousFileName)) { throw new RuntimeException("文件名参数为空!"); } String[] split = ambiguousFileName.split("\\."); return split[0] + suffix; } // -------------------------------- B -------------------------------- // -------------------------------- C -------------------------------- /** * 检查文件 * 0 代表不存在 * 1 代表是文件 * 2 代表是目录 * * @param file 文件 * @return 是否正确 */ public static String checkFile(File file) { if (!file.exists()) { return "0"; } if (file.isFile()) { return "1"; } if (file.isDirectory()) { return "2"; } return null; } /** * 检查文件后缀 * * @param file 文件 * @param suffix 文件后缀 * @return 是否正确 */ public static boolean checkFileType(File file, String suffix) { String fileName = file.getName(); int fileNameLength = fileName.length(); int suffixLength = suffix.length(); if (fileNameLength < suffixLength) { return false; } return suffix.equals(fileName.substring(fileNameLength - suffixLength)); } /** * 自适应转换文件大小的单位 * * @param dataSize long 型的文件大小 * @return 带单位的 String 类型文件大小 */ public static String convertUnit(long dataSize) { String dataSizeStr = null; if (dataSize >= 0 && dataSize < 1024) { dataSizeStr = dataSize + "B"; } else if (dataSize >= 1024 && dataSize < 1024 * 1024) { dataSizeStr = dataSize / 1024 + "KB"; } else if (dataSize >= 1024 * 1024 && dataSize < 1024 * 1024 * 1024) { dataSizeStr = dataSize / 1024 / 1024 + "MB"; } else if (dataSize >= 1024 * 1024 * 1024 && dataSize < 1024 * 1024 * 1024 * 1024L) { dataSizeStr = dataSize / 1024 / 1024 / 1024 + "GB"; } else if (dataSize >= 1024 * 1024 * 1024 * 1024L) { dataSizeStr = dataSize / 1024 / 1024 / 1024 / 1024 + "TB"; } return dataSizeStr; } /** * 计算目录包含的文件数量 * * @param directory 目录的 File 对象 * @return 文件数量 */ public static int count(File directory) { return Objects.requireNonNull(directory.listFiles()).length; } /** * 计算目录包含的文件数量 * * @param directoryPath 目录的路径 * @return 文件数量 */ public static int count(String directoryPath) throws Exception { return count(getDirectory(directoryPath)); } /** * 复制文件 * * @param source 原始文件路径 * @param target 目标路径 * @throws Exception 异常 */ public static void copy(String source, String target) throws Exception { File targetFile = new File(target); boolean delete = true; if (targetFile.exists()) { delete = targetFile.delete(); } if (delete) { createParentDirectory(target); Files.copy(getFile(source).toPath(), new File(target).toPath()); } else { throw new Exception("删除 " + target + " 失败!"); } } /** * 创建目录 */ public static boolean createDirectory(String path) { boolean mkdir = false; File file = new File(path); if (!file.exists()) { mkdir = file.mkdirs(); } return mkdir; } /** * 创建父目录 */ public static boolean createParentDirectory(String path) { boolean mkdir = false; File file = new File(path); if (!file.getParentFile().exists()) { mkdir = file.getParentFile().mkdirs(); } return mkdir; } /** * 创建父目录 */ public static boolean createParentDirectory(File file) { boolean mkdir = true; if (!file.getParentFile().exists()) { mkdir = file.getParentFile().mkdirs(); } return mkdir; } /** * 创建文件。 */ public static boolean createFile(String path) throws IOException { File file = new File(path); boolean result = createParentDirectory(file); if (!file.exists()) { result = file.createNewFile(); } return result; } /** * 创建文件。 */ public static boolean createFile(File file) throws IOException { boolean result = createParentDirectory(file); if (!file.exists()) { result = file.createNewFile(); } return result; } /** * 拷贝文件。 */ public static void copyFile(String readFrom, String writeTo) throws IOException { createParentDirectory(writeTo); FileInputStream fileInputStream = new FileInputStream(readFrom); FileOutputStream fileOutputStream = new FileOutputStream(writeTo); FileChannel readChannel = fileInputStream.getChannel(); FileChannel writeChannel = fileOutputStream.getChannel(); //自动生成与文件大小相同但不超过 8096 的缓存,即缓存最大为 8096。 writeChannel.transferFrom(readChannel, 0, readChannel.size()); writeChannel.close(); readChannel.close(); fileOutputStream.close(); fileInputStream.close(); } public static void copyBytes(InputStream in, OutputStream out, int bufferSize) throws IOException { byte[] buffer = new byte[bufferSize]; for (int bytesRead = in.read(buffer); bytesRead >= 0; bytesRead = in.read(buffer)) { out.write(buffer, 0, bytesRead); } } // -------------------------------- D -------------------------------- /** * 供 http 下载使用 * * @param fileName 文件名 * @param in 输入流 * @param response 响应对象 * @param bufferSize 缓存大小 * @throws IOException 异常 */ public static void downloadForHttp(String fileName, InputStream in, HttpServletResponse response, int bufferSize) throws IOException { response.setContentType("application/octet-stream;charset=utf-8"); response.setHeader("Content-Disposition", "attachment;filename=\"" + fileName + "\""); copyBytes(in, response.getOutputStream(), bufferSize); } public static Set decompress(InputStream inputStream, String targetDirectoryPath, String fileType) throws IOException { Set fileList = new HashSet<>(); if (!targetDirectoryPath.endsWith("/")) { targetDirectoryPath += "/"; } if (".tar".equals(fileType)) { TarArchiveInputStream tarArchiveInputStream = new TarArchiveInputStream(inputStream); TarArchiveEntry entry; // 将 tar 文件解压到 extractPath 目录下 while ((entry = tarArchiveInputStream.getNextTarEntry()) != null) { if (entry.isDirectory()) { continue; } createDirectory(targetDirectoryPath); File currentFile = new File(targetDirectoryPath + entry.getName()); File parent = currentFile.getParentFile(); if (!parent.exists()) { boolean mkdirs = parent.mkdirs(); } fileList.add(currentFile.getAbsolutePath()); // 将文件写出到解压的目录 copyBytes(tarArchiveInputStream, new FileOutputStream(currentFile), 4096); } } if (".tar.gz".equals(fileType)|| ".tgz".equals(fileType)|| ".gz".equals(fileType)) { TarArchiveInputStream tarArchiveInputStream = new TarArchiveInputStream((new GzipCompressorInputStream(inputStream))); TarArchiveEntry entry; // 将 tar 文件解压到 extractPath 目录下 while ((entry = tarArchiveInputStream.getNextTarEntry()) != null) { if (entry.isDirectory()) { continue; } createDirectory(targetDirectoryPath); File currentFile = new File(targetDirectoryPath + entry.getName()); File parent = currentFile.getParentFile(); if (!parent.exists()) { boolean mkdirs = parent.mkdirs(); } fileList.add(currentFile.getAbsolutePath()); // 将文件写出到解压的目录 copyBytes(tarArchiveInputStream, new FileOutputStream(currentFile), 4096); } } inputStream.close(); return fileList; } /** * 扫描压缩包中是否存在指定文件 * @param inputStream * @param fileType * @return * @throws IOException */ public static boolean scan(InputStream inputStream, String fileType, String targetFileName) throws IOException { if (".tar".equals(fileType)) { TarArchiveInputStream tarArchiveInputStream = new TarArchiveInputStream(inputStream); TarArchiveEntry entry; // 将 tar 文件解压到 extractPath 目录下 while ((entry = tarArchiveInputStream.getNextTarEntry()) != null) { if (entry.getName().contains(targetFileName)){ return true; } } } if (".tar.gz".equals(fileType)|| ".tgz".equals(fileType)|| ".gz".equals(fileType)) { TarArchiveInputStream tarArchiveInputStream = new TarArchiveInputStream((new GzipCompressorInputStream(inputStream))); TarArchiveEntry entry; // 将 tar 文件解压到 extractPath 目录下 while ((entry = tarArchiveInputStream.getNextTarEntry()) != null) { if (entry.getName().contains(targetFileName)){ return true; } } } inputStream.close(); return false; } // -------------------------------- F -------------------------------- // -------------------------------- G -------------------------------- /** * 获得去除文件后缀的文件名 */ public static List getAbsolutePathList(File[] files) { List absolutePathList = new ArrayList<>(); for (File file : files) { absolutePathList.add(file.getAbsolutePath()); } return absolutePathList; } /** * 获得目录的 File 对象 */ public static File getDirectory(String path) throws Exception { // 获取文件 File file = new File(path); if (!file.exists()) { throw new Exception("文件" + path + "不存在!"); } if (!file.isDirectory()) { throw new Exception("文件" + path + "不是目录!"); } return file; } /** * 获得去除文件后缀的文件名 */ public static File getFile(String path) throws Exception { // 获取文件 File file = new File(path); if (!file.exists()) { throw new Exception("文件" + path + "不存在!"); } return file; } /** * 获得去除文件后缀的文件名 */ public static String getFilename(File file) { return file.getName().split("\\.")[0]; } /** * 获得去除文件后缀的文件名 */ public static String getFilename(String path) throws Exception { return getFilename(getFile(path)); } /** * 获得去除文件后缀的文件名 */ public static List getFilenameList(File[] files) { List fileNameList = new ArrayList<>(); for (File file : files) { fileNameList.add(file.getName()); } return fileNameList; } /** * 获取文件行数 * * @param path 文件路径 * @return 文件行数 * @throws IOException 异常 */ public static long getFileLineNum(String path) throws IOException { return Files.lines(Paths.get(path)).count(); } /** * 获取文件名称 * * @param path 文件路径 * @return 文件名 */ public static String getFileName(String path) { return new File(path).getName(); } /** * 获取 classpath 文件 * * @param relativePath 相对路径 */ public static File getResourceFile(String relativePath) throws IOException { return ResourceUtils.getFile("classpath:" + relativePath); } /** * 获取所有文件列表。 * * @param root 文件 File 对象。 */ public static List list(File root) throws Exception { List result = new LinkedList<>(); //1 判断文件是否存在 if (!root.exists()) { throw new Exception("文件" + root.getAbsolutePath() + "不存在!"); } //2 判断是否是文件 if (root.isFile()) { return new ArrayList<>(Collections.singletonList(root)); } //3 判断是否是目录 if (root.isDirectory()) { File[] children = root.listFiles(); if (children != null) { for (File child : children) { result.addAll(list(child)); } } } return result; } /** * 获取所有文件列表。 * * @param rootPath 文件 File 对象。 */ public static List list(String rootPath) throws Exception { List result = new ArrayList<>(); File root = new File(rootPath); //1 判断文件是否存在 if (!root.exists()) { throw new Exception("文件" + root.getAbsolutePath() + "不存在!"); } //2 判断是否是文件 if (root.isFile()) { return new ArrayList<>(Collections.singletonList(rootPath)); } //3 判断是否是目录 if (root.isDirectory()) { File[] children = root.listFiles(); if (children != null) { for (File child : children) { result.addAll(list(child.getAbsolutePath())); } } } return result; } /** * 获取所有同一类型的文件列表。 * * @param root 文件 File 对象。 * @param suffix 文件后缀类型。 */ public static List listMatchSuffix(File root, String suffix) throws Exception { List result = new LinkedList<>(); //1 判断文件是否存在 if (!root.exists()) { throw new Exception("文件" + root.getAbsolutePath() + "不存在!"); } //2 判断是否是文件 if (root.isFile() && checkFileType(root, suffix)) { return new ArrayList<>(Collections.singletonList(root)); } //3 判断是否是目录 if (root.isDirectory()) { File[] children = root.listFiles(); if (children != null) { for (File child : children) { result.addAll(listMatchSuffix(child, suffix)); } } } return result; } /** * 获取所有同一名称的文件列表。 * * @param root 文件 File 对象。 * @param fullFilename 带后缀的文件名。 */ public static List listMatchName(File root, String fullFilename) throws Exception { List result = new LinkedList<>(); //1 判断文件是否存在 if (!root.exists()) { throw new Exception("文件" + root.getAbsolutePath() + "不存在!"); } //2 判断是否是文件且文件名是否一致 if (root.isFile() && fullFilename.equals(root.getName())) { return new ArrayList<>(Collections.singletonList(root)); } //3 判断是否是目录 if (root.isDirectory()) { File[] children = root.listFiles(); if (children != null) { for (File child : children) { result.addAll(listMatchName(child, fullFilename)); } } } return result; } /** * 获得父级文件。 * * @return 父级文件 */ public static File getParentFile(String path) throws Exception { return getParentFile(getFile(path)); } /** * 获得父级文件。 * * @return 父级文件 */ public static File getParentFile(File file) { return file.getParentFile(); } /** * 获得父级目录名。 */ public static String getParentDirectoryName(File file) { return getParentFile(file).getName().split("\\.")[0]; } /** * 获得父级目录名。 */ public static String getParentDirectoryName(String path) throws Exception { return getParentDirectoryName(getFile(path)); } /** * 获取路径下的所有文件总大小 */ public static double getSize(File file) throws Exception { //判断文件是否存在 if (file.exists()) { //如果是目录则递归计算其内容的总大小 if (file.isDirectory()) { File[] children = file.listFiles(); if (children == null) { return 0; } double size = 0; for (File f : children) size += getSize(f); return size; } else {//如果是文件则直接返回其大小,以“兆”为单位 return (double) file.length() / 1024 / 1024; } } else { throw new Exception("文件或者文件夹不存在,请检查路径" + file.getAbsolutePath() + "是否正确!"); } } public static String getSuffix(String path) { String[] split = path.split("\\."); return split[split.length - 1]; } /** * 计算文件大小,递归算法 */ public static long getTotalSizeOfFilesInDir(final File file) throws Exception { //判断文件是否存在 if (file.exists()) { if (file.isFile()) { return file.length(); } final File[] children = file.listFiles(); long total = 0; if (children != null) { for (final File child : children) { total += getTotalSizeOfFilesInDir(child); } } return total; } else { throw new Exception("文件或者文件夹不存在,请检查路径" + file.getAbsolutePath() + "是否正确!"); } } // -------------------------------- H -------------------------------- // -------------------------------- I -------------------------------- // -------------------------------- J -------------------------------- // -------------------------------- K -------------------------------- // -------------------------------- L -------------------------------- // -------------------------------- M -------------------------------- /** * 修改文件。 */ public static void modifyFile(String path, int offset, byte[] bytes) throws IOException { createFile(path); RandomAccessFile randomAccessFile = new RandomAccessFile(path, "rw"); FileChannel channel = randomAccessFile.getChannel(); MappedByteBuffer mappedByteBuffer = channel.map(FileChannel.MapMode.READ_WRITE, offset, bytes.length); mappedByteBuffer.put(bytes); channel.close(); } /** * 移动文件或者重命名文件 * * @param source 原始文件路径 * @param target 目标路径 * @return 是否操作成功 * @throws Exception 异常 */ public static boolean mv(String source, String target) throws Exception { return getFile(source).renameTo(new File(target)); } // -------------------------------- N -------------------------------- // -------------------------------- O -------------------------------- // -------------------------------- P -------------------------------- // -------------------------------- Q -------------------------------- // -------------------------------- R -------------------------------- public static String readFile(String path) throws Exception { return readFile(getFile(path)); } public static String readFile(File file) throws Exception { BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file))); StringBuilder stringBuilder = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { stringBuilder.append(line); } reader.close(); return String.valueOf(stringBuilder); } public static String readInputStream(InputStream inputStream) throws Exception { StringBuilder result = new StringBuilder(); byte[] buf = new byte[1024];//创建字节数组,存储临时读取的数据 int len = 0;//记录数据读取的长度 //循环读取数据 while ((len = inputStream.read(buf)) != -1) { //长度为-1则读取完毕 result.append(new String(buf, 0, len)); } inputStream.close(); return result.toString(); } /** * 删除文件或递归删除目录 * 递归删除目录下的所有文件及子目录下所有文件 */ public static boolean rm(File file) { if (!file.exists()) { return false; } else { if (file.isDirectory()) { String[] children = file.list(); if (children != null) { for (String child : children) { if (!rm(new File(file, child))) { return false; } } } return true; } else { return file.delete(); } } } /** * 删除文件或递归删除目录 * 递归删除目录下的所有文件及子目录下所有文件 */ public static boolean rm(String path) { return rm(new File(path)); } // -------------------------------- S -------------------------------- // public static String splicingPath(String... paths) { // StringBuilder result = new StringBuilder(); // for (int i = 0; i < paths.length; i++) { // if (i == 0) { // if ("/".equals(paths[0].charAt(paths.length - 1) + "")) { // String substring = paths[0].substring(0, paths[0].length() - 2); // result.append(substring); // } else { // result.append(paths[0]); // } // } else { // String[] split = paths[i].split("/"); // // for (String s : split) { // if (s != null && !"".equals(s)) { // result.append("/").append(s); // } // } // } // } // return result.toString(); // } // -------------------------------- T -------------------------------- // -------------------------------- U -------------------------------- // -------------------------------- V -------------------------------- // -------------------------------- W -------------------------------- /** * 将字符串保存为本地文件 */ @SneakyThrows public static void writeStringToLocalFile(String string, String filePath) throws IOException { writeInputStreamToLocalFile(new ByteArrayInputStream(string.getBytes(StandardCharsets.UTF_8)), filePath); } /** * 将字符串保存为本地文件 */ @SneakyThrows public static void writeStringToLocalFile(String string, String filePath, int bufferLength) throws IOException { writeInputStreamToLocalFile(new ByteArrayInputStream(string.getBytes(StandardCharsets.UTF_8)), filePath, bufferLength); } /** * 将输入流保存为本地文件 */ public static void writeInputStreamToLocalFile(InputStream inputStream, String filePath) throws IOException { writeInputStreamToLocalFile(inputStream, filePath, 4096); } /** * 将输入流保存为本地文件 */ public static void writeInputStreamToLocalFile(InputStream inputStream, String filePath, int bufferLength) throws IOException { BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream); byte[] data = new byte[bufferLength]; int dataLength; File file = new File(filePath); createParentDirectory(file); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(file, false)); while ((dataLength = bufferedInputStream.read(data)) != -1) { bufferedOutputStream.write(data, 0, dataLength); } bufferedOutputStream.close(); bufferedInputStream.close(); } /** * 将输入流保存为本地文件 */ public static void writeInputStreamToLocalDirectory(InputStream inputStream, String directoryPath, String filename) throws IOException { BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream); byte[] data = new byte[1024]; int dataLength; File file = new File(directoryPath + File.separator + filename); createDirectory(directoryPath); createFile(file); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(file, false)); while ((dataLength = bufferedInputStream.read(data)) != -1) { bufferedOutputStream.write(data, 0, dataLength); } bufferedOutputStream.close(); bufferedInputStream.close(); } }