【文件 IO 流的常用操作工具类】

package com.lfsun.common.util;

import com.google.common.io.CharSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.servlet.http.HttpServletResponse;
import javax.swing.filechooser.FileSystemView;
import java.io.*;
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * 文件 IO 流的常用操作工具类
 *
 * @author lfsun666
 */
public class IOUtils {
    public static final Logger logger = LoggerFactory.getLogger(IOUtils.class);

    /**
     * 读取指定路径的文件内容,并将其转化为字符串返回
     *
     * @param filePath 文件路径
     * @return 文件内容
     * @throws IOException 如果读取文件时出现异常
     */
    public static String readFile(String filePath) {
        StringBuilder contentBuilder = new StringBuilder();
        try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
            String sCurrentLine;
            while ((sCurrentLine = br.readLine()) != null) {
                contentBuilder.append(sCurrentLine).append("\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return contentBuilder.toString();
    }

    /**
     * 将指定字符串写入到指定路径的文件中
     *
     * @param filePath 文件路径
     * @param content  文件内容
     * @throws IOException 如果写文件时出现异常
     */
    public static void writeFile(String filePath, String content) throws IOException {
        // 创建文件对象
        File file = new File(filePath);

        // 检查文件路径是否存在,如果不存在则创建
        File parentDir = file.getParentFile();
        if (null != parentDir) {
            // 没有父级目录
            if (!parentDir.exists()) {
                if (!parentDir.mkdirs()) {
                    throw new IOException("写入指定路径失败: " + parentDir);
                }
            }

            // 检查文件是否存在,如果不存在则创建
            if (!file.exists()) {
                if (!file.createNewFile()) {
                    throw new IOException("创建文件失败: " + file);
                }
            }
        }
        // 打开文件输出流
        try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(file.toPath()), StandardCharsets.UTF_8))) {
            // 写入数据
            bw.write(content);
        } catch (IOException e) {
            throw new IOException("Failed to write file: " + file, e);
        }
    }


    /**
     * 创建指定路径的目录
     *
     * @param directoryPath 文件夹路径
     */
    public static void createDirectory(String directoryPath) {
        File directory = new File(directoryPath);
        if (!directory.exists()) {
            directory.mkdirs();
        }
    }

    /**
     * 使用 ObjectOutputStream 和 ObjectInputStream 进行对象的序列化和反序列化时,
     * 建议不要使用字符流 InputStreamReader 和 OutputStreamWriter。应该直接读写对象,
     * 这样可以保证数据的完整性和正确性。因为对象中可能会包含二进制数据,使用字符流会将其解析成不可预料的字符,导致数据损坏。
     * 

* 如果要保证序列化后的文件是以 UTF-8 编码的文本文件,可以先将对象序列化到一个字节数组中, * 然后再将字节数组写入文件。反序列化时,先读取文件中的字节数组,然后再从字节数组中反序列化出对象。 *

*

* 将指定的对象序列化后写入到指定路径的文件中 * * @param filePath 文件路径 * @param obj 待序列化的对象 * @throws IOException 如果序列化对象时出现异常 */ public static void writeObjectToFile(String filePath, Object obj) { try (ObjectOutputStream oos = new ObjectOutputStream(Files.newOutputStream(Paths.get(filePath)))) { oos.writeObject(obj); } catch (IOException e) { e.printStackTrace(); } } /** * 从指定路径的文件中读取对象并反序列化 * * @param filePath 文件路径 * @return 反序列化得到的对象 * @throws IOException 如果反序列化对象时出现异常 * @throws ClassNotFoundException 如果反序列化得到的对象无法转换为已知的类 */ public static Object readObjectFromFile(String filePath) { try (ObjectInputStream ois = new ObjectInputStream(Files.newInputStream(Paths.get(filePath)))) { return ois.readObject(); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } return null; } /** * 将指定源文件复制到指定目标文件中 * * @param source 源文件 * @param dest 目标文件 * @throws IOException 如果复制文件时出现异常 */ public static void copyFile(File source, File dest) throws IOException { try (InputStream is = Files.newInputStream(source.toPath()); OutputStream os = Files.newOutputStream(dest.toPath())) { byte[] buffer = new byte[1024]; int length; while ((length = is.read(buffer)) > 0) { os.write(buffer, 0, length); } } } /** * 压缩指定文件或目录 * * @param source 要压缩的文件或目录 * @param dest 压缩后的文件 * @throws IOException 如果压缩文件时出现异常 */ public static void zipFile(File source, File dest) throws IOException { try (ZipOutputStream zs = new ZipOutputStream(Files.newOutputStream(dest.toPath()))) { String path = source.getPath(); if (source.isDirectory()) { for (File file : Objects.requireNonNull(source.listFiles())) { addToZip(path, file, zs, dest.getPath()); } } else { addToZip(path, source, zs, dest.getPath()); } } } /** * 将指定文件或文件夹添加到 ZipOutputStream 中 * * basePath 参数应该传入文件或文件夹的父目录的路径,而不是文件或文件夹的路径本身。 * * zs 参数需要在调用该方法之前创建,并在使用完成后关闭,以确保所有数据都被写入到 ZipOutputStream 中。 * * 由于 ZipEntry 的名称需要使用 / 分隔符,而 Windows 平台下文件路径使用的是 \ 分隔符,因此需要将路径中的 \ 替换为 /。 * * 如果要压缩的文件或文件夹中包含中文等非 ASCII 字符,需要使用正确的编码方式进行转换,避免乱码或文件名不正确的问题。 * * @param basePath 文件或文件夹的基础路径,用于计算 ZipEntry 的名称 * @param file 要添加到 ZipOutputStream 的文件或文件夹 * @param zs ZipOutputStream,用于添加文件或文件夹 * @param selfPath zip文件本身的路径 * @throws IOException 如果无法读取文件或写入到 ZipOutputStream,则抛出 IOException */ private static void addToZip(String basePath, File file, ZipOutputStream zs, String selfPath) throws IOException { String filePath = file.getPath(); String zipEntryName = filePath.substring(basePath.length() + 1); if (file.isDirectory()) { for (File f : Objects.requireNonNull(file.listFiles())) { addToZip(basePath, f, zs, selfPath); } } else { // 跳过源文件夹本身 比如 *.zip if (file.getPath().equals(selfPath)) { return; } byte[] buffer = new byte[1024]; int length; try (FileInputStream fis = new FileInputStream(file)) { zs.putNextEntry(new ZipEntry(zipEntryName)); while ((length = fis.read(buffer)) > 0) { zs.write(buffer, 0, length); } } } } /** * 将指定 Zip 文件解压到指定目录中 * * @param zipFilePath 要解压的 Zip 文件的路径 * @param destDirectory 解压目录的路径 * @throws IOException 如果无法读取 Zip 文件或解压文件,则抛出 IOException */ public static void unzip(String zipFilePath, String destDirectory) throws IOException { File destDir = new File(destDirectory); if (!destDir.exists()) { destDir.mkdir(); } // 打开 ZipInputStream,并迭代解压每个 ZipEntry ZipInputStream zipIn = new ZipInputStream(Files.newInputStream(Paths.get(zipFilePath))); ZipEntry entry = zipIn.getNextEntry(); // 迭代解压每一个文件 while (entry != null) { String filePath = destDirectory + File.separator + entry.getName(); if (!entry.isDirectory()) { // 如果是文件,解压文件 extractFile(zipIn, filePath); } else { // 如果是目录,创建目录 File dir = new File(filePath); dir.mkdir(); } zipIn.closeEntry(); entry = zipIn.getNextEntry(); } zipIn.close(); } /** * 将指定 ZipEntry 的内容解压到指定文件中 * * @param zipIn ZipInputStream,用于读取 ZipEntry 的内容 * @param filePath 解压文件的路径 * @throws IOException 如果无法读取 ZipEntry 的内容或写入到解压文件,则抛出 IOException */ private static void extractFile(ZipInputStream zipIn, String filePath) throws IOException { BufferedOutputStream bos = new BufferedOutputStream(Files.newOutputStream(Paths.get(filePath))); byte[] bytesIn = new byte[4096]; int read; while ((read = zipIn.read(bytesIn)) != -1) { bos.write(bytesIn, 0, read); } bos.close(); } /** * 将字符串写入到指定文件中 * * @param content 写入的字符串 * @param file 指定的文件 * @throws IOException */ public static void writeStringToFile(String content, File file) throws IOException { try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { writer.write(content); } } /** * 读取给定文件并将其转换为字符串列表。 * * @param file 要读取的文件 * @return 文件内容的字符串列表 * @throws IOException 如果文件无法读取或发生其他 I/O 错误 */ public static List<String> readTextFileToList(File file) throws IOException { try (BufferedReader reader = new BufferedReader(new FileReader(file))) { List<String> lines = new ArrayList<>(); String line; while ((line = reader.readLine()) != null) { lines.add(line); } return lines; } } /** * 按指定大小将大文件拆分为多个小文件。 * * @param inputFile 要拆分的文件 * @param splitSize 拆分文件的大小,单位 byte * @throws IOException 如果文件无法读取或发生其他 I/O 错误 */ public static void splitFile(File inputFile, long splitSize) throws IOException { int splitNumber = (int) Math.ceil(inputFile.length() * 1.0 / splitSize); try (BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(inputFile.toPath()))) { byte[] buffer = new byte[(int) splitSize]; for (int i = 0; i < splitNumber; i++) { File outFile = new File(inputFile.getParent(), inputFile.getName() + "-" + i); try (BufferedOutputStream bos = new BufferedOutputStream(Files.newOutputStream(outFile.toPath()))) { int readSize = bis.read(buffer); bos.write(buffer, 0, readSize); } } } } /** * 将多个小文件合并为一个大文件。 * * @param outFile 合并后的输出文件 * @param inputFiles 要合并的文件列表 * @throws IOException 如果文件无法读取或发生其他 I/O 错误 */ public static void mergeFiles(File outFile, List<File> inputFiles) throws IOException { try (BufferedOutputStream bos = new BufferedOutputStream(Files.newOutputStream(outFile.toPath()))) { for (File inputFile : inputFiles) { try (BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(inputFile.toPath()))) { byte[] buffer = new byte[4096]; int readSize; while ((readSize = bis.read(buffer)) > 0) { bos.write(buffer, 0, readSize); } } } } } /** * 递归删除文件或目录。 * * @param file 要删除的文件或目录 */ public static void delete(File file) { if (file.isDirectory()) { // 判断是否为目录 File[] files = file.listFiles(); // 获取目录下的所有文件和文件夹 if (files != null) { // 判断是否为空目录 for (File f : files) { delete(f); // 递归调用delete方法,删除所有文件和文件夹 } } } file.delete(); // 删除文件或空目录 } /** * 使用Files.walk()方法获取所有文件和文件夹,并利用lambda表达式实现遍历和删除。 * * @param path 要删除的目录路径 * @throws IOException 如果删除文件或文件夹时发生错误,抛出IOException异常 */ public static void delete(Path path) throws IOException { Files.walk(path) // 获取path及其子目录下的所有文件和文件夹 .sorted((p1, p2) -> -p1.compareTo(p2)) // 倒序排列,先删除子目录下的文件和文件夹 .forEach(p -> { try { Files.delete(p); // 删除文件或文件夹 } catch (IOException e) { e.printStackTrace(); } }); } /** * 删除指定目录下创建时间超过指定天数的文件和空目录。 * 如果要对整个目录进行递归操作,或者需要处理一些删除异常的情况,建议使用 * * @param dir 待清理的目录 * @param days 文件最大存活天数 // -1 表示立即删除 * @throws IOException 如果清理目录失败抛出IOException异常 */ public static void cleanTempDir(Path dir, int days) throws IOException { Instant now = Instant.now(); // 使用Files.walkFileTree()方法遍历目录,实现文件和目录的删除 Files.walkFileTree(dir, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { Instant fileCreationTime = attrs.creationTime().toInstant(); long ageInDays = ChronoUnit.DAYS.between(fileCreationTime, now); if (ageInDays > days) { // if (ageInDays >= days) { // 不包括临界值 Files.delete(file); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { if (!Files.list(dir).findAny().isPresent()) { Files.delete(dir); } return FileVisitResult.CONTINUE; } }); } /** * 如果目录比较大或者需要高效地删除目录,建议使用 * 删除指定目录下创建时间超过指定天数的文件和空目录。建议使用此方法来删除大目录或需要高效删除目录的情况。 * * @param directory 待清理的目录 * @param daysToKeep 文件最大保留天数 // -1 表示立即删除 * @throws IOException 如果删除目录失败抛出IOException异常 */ public static void cleanDirectory(Path directory, int daysToKeep) throws IOException { Instant now = Instant.now(); // 使用Files.walk()方法获取所有文件和文件夹,并利用lambda表达式实现遍历和删除。 Files.walk(directory) .sorted(Comparator.reverseOrder()) .forEach(path -> { try { BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class); Instant creationTime = attrs.creationTime().toInstant(); long ageInDays = ChronoUnit.DAYS.between(creationTime, now); if (ageInDays > daysToKeep) { // if (ageInDays >= daysToKeep) { Files.delete(path); // 如果文件/文件夹的创建时间超过了保留天数,则删除它。 } else if (Files.isDirectory(path) && !Files.list(path).findAny().isPresent()) { Files.delete(path); // 如果是空目录,则删除它。 } } catch (IOException e) { System.err.println("删除失败: " + path + ": " + e.getMessage()); } }); /* 示例用法: Path directory = Paths.get("C:/temp"); cleanDirectory(directory, 30); // 删除C:/temp下创建时间超过30天的文件和空目录。 */ } /** * 递归删除指定目录下创建时间超过指定天数的文件和空目录。(与前两个不同的是这个方法只删除里面的文件,不删除根目录。也就是清空指定文件夹的内容) * * @param directory 待清理的目录 * @param daysToKeep 文件最大存活天数 // -1 表示立即删除 * @throws IOException 如果清理目录失败抛出IOException异常 */ public static void cleanDirectoryRecursively(Path directory, int daysToKeep) throws IOException { File[] files = directory.toFile().listFiles(); // 获取目录下的所有文件和文件夹 if (files == null) { // 目录不存在或无法访问,直接返回 return; } for (File file : files) { // 遍历目录下的所有文件和文件夹 if (file.isDirectory()) { // 如果是文件夹 cleanDirectoryRecursively(file.toPath(), daysToKeep); // 递归调用本方法,清理文件夹内的文件和文件夹 //if (file.list().length == 0 && Duration.between(FileTime.fromMillis(file.lastModified()).toInstant(), FileTime.from(Instant.now()).toInstant()).toDays() >= daysToKeep) { if (Objects.requireNonNull(file.list()).length == 0 && Duration.between(FileTime.fromMillis(file.lastModified()).toInstant(), FileTime.from(Instant.now()).toInstant()).toDays() > daysToKeep) { Files.deleteIfExists(file.toPath()); // 如果文件夹为空且创建时间超过了保留天数,则删除它。 } } else { // 如果是文件 if (Duration.between(FileTime.fromMillis(file.lastModified()).toInstant(), FileTime.from(Instant.now()).toInstant()).toDays() > daysToKeep) { Files.deleteIfExists(file.toPath()); // 如果文件的创建时间超过了保留天数,则删除它。 } } } } /** * 下载并解压缩指定 URL 的 ZIP 文件。 * * @param url 要下载的 ZIP 文件的 URL * @param targetDirPath 下载并解压缩后文件的存放目录 * @throws IOException 如果文件下载或解压缩过程中出现错误则抛出 IOException 异常 */ public static void downloadAndUnzip(URL url, Path targetDirPath) throws IOException { // 下载文件 InputStream inputStream = url.openStream(); File tempFile = File.createTempFile("temp-", ".zip"); Path path = tempFile.toPath(); Files.copy(inputStream, path, StandardCopyOption.REPLACE_EXISTING); inputStream.close(); // 解压缩文件 try (ZipInputStream zipInputStream = new ZipInputStream(Files.newInputStream(path))) { ZipEntry zipEntry; while ((zipEntry = zipInputStream.getNextEntry()) != null) { Path entryPath = targetDirPath.resolve(zipEntry.getName()); if (zipEntry.isDirectory()) { Files.createDirectories(entryPath); } else { Files.createDirectories(entryPath.getParent()); Files.copy(zipInputStream, entryPath, StandardCopyOption.REPLACE_EXISTING); } zipInputStream.closeEntry(); } } tempFile.delete(); } /** * 下载并解压缩指定URL的压缩文件到指定目录 * * @param urlStr 文件的URL地址 * @param destDir 目标文件夹 * @throws IOException */ public static void downloadAndUnzip(String urlStr, String destDir) throws IOException { URL url = new URL(urlStr); // 使用Java NIO中的Channels和Buffers来提高下载效率 ReadableByteChannel byteChannel = Channels.newChannel(url.openStream()); FileOutputStream outputStream = new FileOutputStream(destDir); FileChannel fileChannel = outputStream.getChannel(); ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024); while (byteChannel.read(buffer) != -1) { buffer.flip(); fileChannel.write(buffer); buffer.clear(); } byteChannel.close(); fileChannel.close(); outputStream.close(); // 对下载下来的压缩文件进行解压缩 try (ZipFile zipFile = new ZipFile(destDir)) { Enumeration<? extends ZipEntry> entries = zipFile.entries(); while (entries.hasMoreElements()) { ZipEntry entry = entries.nextElement(); Path entryDestination = Paths.get(destDir, entry.getName()); if (entry.isDirectory()) { Files.createDirectories(entryDestination); } else { Files.createDirectories(entryDestination.getParent()); InputStream inputStream = zipFile.getInputStream(entry); Files.copy(inputStream, entryDestination, StandardCopyOption.REPLACE_EXISTING); inputStream.close(); } } } catch (IOException e) { e.printStackTrace(); } } /** * 下载文件并解压缩到指定目录 * * @param url 文件的 URL 地址 * @param targetDir 目标目录,如果不存在将被创建 * @throws IOException 如果下载或解压缩失败抛出 IOException 异常 */ public static void downloadAndUnzip(String url, Path targetDir) throws IOException { URLConnection connection = new URL(url).openConnection(); try (InputStream in = connection.getInputStream()) { Path tempFile = Files.createTempFile("download-", ".tmp"); Files.copy(in, tempFile, StandardCopyOption.REPLACE_EXISTING); try (ZipFile zip = new ZipFile(tempFile.toFile())) { zip.stream().forEach(entry -> { try { Path path = targetDir.resolve(entry.getName()); if (entry.isDirectory()) { Files.createDirectories(path); } else { Files.copy(zip.getInputStream(entry), path, StandardCopyOption.REPLACE_EXISTING); } } catch (IOException e) { throw new UncheckedIOException(e); } }); } Files.delete(tempFile); } } /** * 下载指定 URL 的文件,并保存到指定目录。 * * @param url 要下载的文件的 URL * @param savePath 保存文件的目录路径 * @throws IOException 如果下载失败,抛出 IOException 异常 */ public static void downloadFile(String url, Path savePath) throws IOException { try (InputStream in = new URL(url).openStream()) { Files.copy(in, savePath, StandardCopyOption.REPLACE_EXISTING); } catch (IOException e) { throw new IOException("下载文件失败: " + url, e); } } /** * 下载指定URL的文件并保存到指定路径。 * * @param urlStr 文件URL * @param saveDir 保存目录 * @param fileName 保存文件名 * @throws IOException 如果下载或保存失败抛出IOException异常 */ public static void downloadFile(String urlStr, String saveDir, String fileName) throws IOException { URL url = new URL(urlStr); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); conn.setReadTimeout(5000); try (BufferedInputStream in = new BufferedInputStream(conn.getInputStream())) { Path savePath = Paths.get(saveDir, fileName); Files.copy(in, savePath); } finally { conn.disconnect(); } } /** * 解压缩指定路径下的指定压缩文件到指定目录下。 * * @param filePath 压缩文件路径 * @param outputDir 解压缩输出目录 * @throws IOException 如果解压缩失败抛出IOException异常 */ public static void extract(String filePath, String outputDir) throws IOException { try (ZipInputStream zipIn = new ZipInputStream(Files.newInputStream(Paths.get(filePath)))) { ZipEntry entry; while ((entry = zipIn.getNextEntry()) != null) { String entryName = entry.getName(); Path entryPath = Paths.get(outputDir, entryName); if (entry.isDirectory()) { Files.createDirectories(entryPath); } else { Files.createDirectories(entryPath.getParent()); Files.copy(zipIn, entryPath); } zipIn.closeEntry(); } } } /** * 下载指定URL的压缩文件并解压缩到指定目录下。 * * @param urlStr 压缩文件URL * @param outputDir 解压缩输出目录 * @throws IOException 如果下载、解压缩或清理临时文件失败抛出IOException异常 */ public static void downloadAndExtract(String urlStr, String outputDir) throws IOException { Path tempDir = Files.createTempDirectory("temp"); // 创建临时目录 String fileName = urlStr.substring(urlStr.lastIndexOf('/') + 1); String filePath = tempDir.resolve(fileName).toString(); try { downloadFile(urlStr, tempDir.toString(), fileName); extract(filePath, outputDir); } finally { cleanDirectoryRecursively(tempDir, 0); // 清理临时目录 } } /** * 下载指定 URL 的压缩文件,并解压到指定目录。 * * @param url 要下载的压缩文件的 URL * @param extractTo 解压文件的目录路径 * @throws IOException 如果下载或解压失败,抛出 IOException 异常 */ public static void downloadAndExtract(String url, Path extractTo) throws IOException { try (InputStream in = new URL(url).openStream()) { // 下载文件并保存到临时文件中 Path tempFile = Files.createTempFile("download", ".zip"); Files.copy(in, tempFile, StandardCopyOption.REPLACE_EXISTING); // 解压文件到指定目录中 extract(tempFile.toFile().getPath(), extractTo.toFile().getPath()); // 删除临时文件 Files.deleteIfExists(tempFile); } catch (IOException e) { throw new IOException("下载或解压文件失败: " + url, e); } } /** * 列出当前系统中所有的磁盘卷标名称 * * @return 磁盘卷标名称列表 */ public static List<String> listDisks() { List<String> disks = new ArrayList<>(); // 存放磁盘卷标的列表 FileSystemView fileSystemView = FileSystemView.getFileSystemView(); // 获取文件系统视图对象 File[] roots = File.listRoots(); // 获取系统的根目录列表 for (File root : roots) { // 遍历根目录列表 disks.add(fileSystemView.getSystemDisplayName(root)); // 获取磁盘卷标并添加到列表中 } return disks; // 返回磁盘卷标列表 } /** * 下载文件字节数组。 * * @param response HTTP响应对象 * @param fileData 文件字节数组 * @param fileName 下载文件名,需要包括文件后缀 * @throws Exception 如果下载文件名不包含后缀,抛出异常 */ public static void downloadByteArray(final HttpServletResponse response, byte[] fileData, String fileName) throws Exception { if (!fileName.contains(".")) { throw new Exception("文件名必须包含后缀"); } response.reset(); response.setCharacterEncoding("UTF-8"); response.setContentType("application/form-data"); response.setHeader("Content-Disposition", "attachment; filename=" + new String(fileName.getBytes(), "ISO8859-1")); response.setHeader("Set-Cookie", "fileDownload=true; path=/"); OutputStream out = response.getOutputStream(); out.write(fileData); out.flush(); out.close(); } /** * 下载指定路径下的文件。 * * @param response HTTP响应对象 * @param filePath 文件完整路径,包括文件名和扩展名 * @param fileName 下载后看到的文件名 * @throws Exception 如果读取文件字节数组出现异常,则抛出异常 */ public static void downloadFile(final HttpServletResponse response, String filePath, String fileName) throws Exception { byte[] data = toByteArray(filePath); downloadByteArray(response, data, fileName); } /** * @param dir 文件路径 * @param realName 文件名 * @throws IOException * @Description:判断路径是否存在,否:创建此路径 */ public static File mkdirs(String dir, String realName) throws IOException { File file = new File(dir, realName); if (!file.exists()) { if (!file.getParentFile().exists()) { file.getParentFile().mkdirs(); } if (!file.createNewFile()) { logger.error("创建文件失败"); } } return file; } /** * @param httpUrl 图片网络地址 * @param filePath 图片保存路径 * @param myFileName 图片文件名(null时用网络图片原名) * @return 返回图片名称 * @Description:下载网络图片上传到服务器上 */ public static String getHtmlPicture(String httpUrl, String filePath, String myFileName) { //定义URL对象url String fileName = null; try (BufferedInputStream in = new BufferedInputStream(new URL(httpUrl).openStream()); FileOutputStream file = new FileOutputStream(mkdirs(filePath, (fileName = (myFileName == null ? httpUrl.substring(httpUrl.lastIndexOf("/")).replace("/", "") : myFileName))))) { int t; while ((t = in.read()) != -1) { file.write(t); } } catch (IOException e) { logger.error("上传文件异常", e); } return fileName; } /** * 获取文件大小(单位:KB,保留3位小数) * * @param filepath 文件完整路径,包括文件名 * @return 文件大小,没有文件时返回0 */ public static double getFilesize(String filepath) { return new File(filepath).length() / 1000.0; } /** * 创建目录(包括不存在的父目录) * * @param destDirName 目标目录名 * @return 是否创建成功 */ public static boolean createDir(String destDirName) { File dir = new File(destDirName); if (dir.exists()) { return true; // 目录已存在 } return dir.mkdirs(); // 创建目录(包括不存在的父目录) } /** * 删除文件 * * @param filePathAndName 文件路径及名称,如c:/fqf.txt * @return 是否删除成功 */ public static boolean delFile(String filePathAndName) { try { File file = new File(filePathAndName); if (file.exists()) { return file.delete(); // 删除文件 } return true; // 文件不存在,视为删除成功 } catch (Exception e) { logger.error("删除文件操作出错", e); return false; // 删除文件出错,视为删除失败 } } /** * 读取到字节数组 * * @param filePath 文件路径 * @return 字节数组 * @throws IOException 读取文件出错 */ public static byte[] toByteArray(String filePath) throws IOException { Path path = Paths.get(filePath); return Files.readAllBytes(path); // 直接使用Java7提供的Files工具类,实现读取文件到字节数组 } /** * 读取到ByteBuffer * * @param filePath 文件路径 * @return ByteBuffer * @throws IOException 读取文件出错 */ public static ByteBuffer toByteBuffer(String filePath) throws IOException { try (RandomAccessFile raf = new RandomAccessFile(filePath, "r")) { FileChannel channel = raf.getChannel(); return channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size()); // 使用NIO提供的MappedByteBuffer,实现读取文件到ByteBuffer } catch (IOException e) { logger.error("读取到ByteBuffer出错", e); throw e; } } /** * 复制classpath下的文件到jar包的同级目录下 * * @param location 相对路径文件,例如kafka/kafka_client_jaas.conf * @return 目标文件的绝对路径 * @throws IOException */ public static String copy(String location) throws IOException { // 获取输入流 InputStream in = getResource("classpath:" + location); // 获取目标文件路径 Path dist = getDistFile(location); // 复制文件到目标路径 Files.copy(in, dist); // 关闭输入流 in.close(); // 返回目标文件的绝对路径 return dist.toAbsolutePath().toString(); } /** * 获取指定路径的资源输入流 * * @param location 资源路径 * @return 输入流 * @throws IOException */ private static InputStream getResource(String location) throws IOException { PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); // 获取资源输入流 InputStream in = resolver.getResource(location).getInputStream(); // 将输入流中的内容读取到字节数组中 byte[] byteArray = org.apache.commons.io.IOUtils.toByteArray(in); // 关闭输入流 in.close(); // 将字节数组包装为新的输入流并返回 return new ByteArrayInputStream(byteArray); } /** * 获取目标文件路径 * * @param path 文件相对路径 * @return 目标文件路径 * @throws IOException */ private static Path getDistFile(String path) throws IOException { // 获取当前工作目录路径 String currentRealPath = System.getProperty("user.dir"); // 构造目标文件路径 Path dist = Paths.get(currentRealPath + File.separator + path); // 创建目录 Path parent = dist.getParent(); if (parent != null) { Files.createDirectories(parent); } // 删除已存在的目标文件 Files.deleteIfExists(dist); // 返回目标文件路径 return dist; } /** * 根据文件路径读取byte[] 数组 * * @param filePath 文件路径 * @return byte[] 数组 * @throws IOException */ public static byte[] readFileByBytes(String filePath) throws IOException { File file = new File(filePath); if (!file.exists()) { throw new FileNotFoundException(filePath); } else { try (ByteArrayOutputStream bos = new ByteArrayOutputStream((int) file.length())) { BufferedInputStream in; in = new BufferedInputStream(Files.newInputStream(file.toPath())); // 定义缓冲区大小 short bufSize = 1024; byte[] buffer = new byte[bufSize]; int len1; while (-1 != (len1 = in.read(buffer, 0, bufSize))) { bos.write(buffer, 0, len1); } // 返回读取的字节数组 return bos.toByteArray(); } // 关闭输入流和输出流 } } /** * 将输入流转换为字符串(使用 JDK 原生提供的方法) * * @param inputStream 输入流 * @return 转换后的字符串 * @throws IOException 如果发生 I/O 异常 */ public static String inputStream2Str(InputStream inputStream) throws IOException { ByteArrayOutputStream result = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int length; while ((length = inputStream.read(buffer)) != -1) { result.write(buffer, 0, length); } return result.toString(StandardCharsets.UTF_8.name()); } /** * 将输入流转换为字符串(使用 Apache Commons 提供的方法) * * @param inputStream 输入流 * @return 转换后的字符串 * @throws IOException 如果发生 I/O 异常 */ public static String inputStream2StrByApacheCommons(InputStream inputStream) throws IOException { return org.apache.commons.io.IOUtils.toString(inputStream, StandardCharsets.UTF_8.name()); } /** * 将字符串转换为输入流(使用 JDK 原生提供的方法) * * @param str 字符串 * @return 转换后的输入流 */ public static InputStream str2InputStream(String str) { return new ByteArrayInputStream(str.getBytes()); } /** * 将字符串转换为输入流(使用 Apache Commons 提供的方法) * * @param str 字符串 * @return 转换后的输入流 * @throws IOException 如果发生 I/O 异常 */ public static InputStream str2InputStreamByApacheCommons(String str) throws IOException { return org.apache.commons.io.IOUtils.toInputStream(str, StandardCharsets.UTF_8.name()); } /** * 将字符串转换为输入流(使用 Apache Commons 提供的 ReaderInputStream 类) * * @param str 字符串 * @return 转换后的输入流 * @throws IOException 如果发生 I/O 异常 */ public static InputStream str2InputStreamByGoogleGuava(String str) throws IOException { // 使用 Apache Commons 提供的 ReaderInputStream 类 return new org.apache.commons.io.input.ReaderInputStream(CharSource.wrap(str).openStream(), StandardCharsets.UTF_8.name()); } /** * 从类路径下获取文件的路径 * * @param filename 文件名 * @return 文件的路径 */ public static String getClasspathFilePath(String filename) { // 获取类加载器 ClassLoader classLoader = IOUtils.class.getClassLoader(); // 获取文件的 URL URL url = classLoader.getResource(filename); if (url == null) { throw new IllegalArgumentException("文件找不到: " + filename); } // URL 转换为 URI URI uri; try { uri = url.toURI(); } catch (URISyntaxException e) { throw new IllegalArgumentException("无效的 URL: " + url, e); } // 获取文件路径 File file = new File(uri); return file.getAbsolutePath(); } private static final ResourceLoader RESOURCE_LOADER; static { // 初始化 ResourceLoader RESOURCE_LOADER = new DefaultResourceLoader(); } /** * 获取资源加载器(可读取 jar 内的文件) * * @return 资源加载器 */ public static ResourceLoader getResourceLoader() { return RESOURCE_LOADER; } /** * 获取 ClassLoader * * @return ClassLoader */ public static ClassLoader getClassLoader() { return RESOURCE_LOADER.getClassLoader(); } /** * 获取指定位置的资源 * * @param location 资源位置,可以是文件系统路径或类路径 * @return Resource 对象 */ public static Resource getSpringResource(String location) { return RESOURCE_LOADER.getResource(location); } /** * 获取指定位置的资源文件流 * * @param location 资源位置,可以是文件系统路径或类路径 * @return InputStream 输入流 * @throws IOException 如果发生 I/O 异常 */ public static InputStream getResourceFileStream(String location) throws IOException { Resource resource = RESOURCE_LOADER.getResource(location); return resource.getInputStream(); } }

测试:

package com.lfsun.common.util;

import com.lfsun.common.constant.CommonConstant;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

class IOUtilsTest {

    //         public static final String RESOURCES_PATH = "src" + File.separator + "main" + File.separator + "resources";

    @Test
    void readFile() {
        System.out.println(IOUtils.getClasspathFilePath("a1.txt"));
        System.out.println(IOUtils.readFile(IOUtils.getClasspathFilePath("a1.txt")));
    }

    @Test
    void writeFile() throws IOException {
        IOUtils.writeFile("a1.txt", "修改后的文件!");
        IOUtils.writeFile(CommonConstant.RESOURCES_PATH + "/a1.txt", "修改后的文件!");
    }

    @Test
    void createDirectory() {
        IOUtils.createDirectory(CommonConstant.RESOURCES_PATH + "/createDirectory");
    }

    @Test
    void writeObjectToFile() {
        IOUtils.writeObjectToFile(CommonConstant.RESOURCES_PATH + "/a3.txt", "字符串1");
    }

    @Test
    void readObjectFromFile() {
        System.out.println(IOUtils.readObjectFromFile(CommonConstant.RESOURCES_PATH + "/a3.txt"));
    }

    @Test
    void copyFile() throws IOException {
        IOUtils.copyFile(new File(CommonConstant.RESOURCES_PATH + "/a3.txt"), new File(CommonConstant.RESOURCES_PATH + "/a3-copy.txt"));
        System.out.println(IOUtils.readObjectFromFile(CommonConstant.RESOURCES_PATH + "/a3-copy.txt"));
    }

    @Test
    void zipFile() throws IOException {
        IOUtils.zipFile(new File(CommonConstant.RESOURCES_PATH + "/my"), new File(CommonConstant.RESOURCES_PATH + "/my/my-zip.zip"));
    }

    @Test
    void unzip() throws IOException {
        IOUtils.unzip(CommonConstant.RESOURCES_PATH + "/my/my-zip.zip", CommonConstant.RESOURCES_PATH + "/my/my-zip");
    }

    @Test
    void writeStringToFile() throws IOException {
        IOUtils.writeStringToFile("这是一个测试字符串", new File(CommonConstant.RESOURCES_PATH + "/a4.txt"));
    }

    @Test
    void readTextFileToList() throws IOException {
        List<String> list = IOUtils.readTextFileToList(new File(CommonConstant.RESOURCES_PATH + "/a4-strs.txt"));
        if (!list.isEmpty()) {
            list.forEach(System.out::println);
        }
    }

    @Test
    void splitFile() throws IOException {
        IOUtils.splitFile(new File(CommonConstant.RESOURCES_PATH + "/a5-big.txt"), 1000);
    }

    @Test
    void mergeFiles() throws IOException {
        List<File> fileList = new ArrayList<>();
        fileList.add(new File(CommonConstant.RESOURCES_PATH + "/a5-big.txt" + "-0"));
        fileList.add(new File(CommonConstant.RESOURCES_PATH + "/a5-big.txt" + "-1"));
        IOUtils.mergeFiles(new File(CommonConstant.RESOURCES_PATH + "/a5-merge.txt"), fileList);
    }

    @Test
    void delete() {
        // IOUtils.delete(new File(CommonConstant.RESOURCES_PATH + "/a5-merge.txt"));
        IOUtils.delete(new File(CommonConstant.RESOURCES_PATH + "/my/my-zip"));
    }

    @Test
    void testDelete() throws IOException {
        // IOUtils.delete(Paths.get(CommonConstant.RESOURCES_PATH + "/my/my-zip.zip"));
        IOUtils.delete(Paths.get(CommonConstant.RESOURCES_PATH + "/my/my-zip"));
    }

    @Test
    void cleanTempDir() throws IOException {
        IOUtils.cleanTempDir(Paths.get(CommonConstant.RESOURCES_PATH + "/my/my-zip"), -1);
    }

    @Test
    void cleanDirectory() throws IOException {

        IOUtils.cleanDirectory(Paths.get(CommonConstant.RESOURCES_PATH + "/my/my-zip"), -1);
    }

    @Test
    void cleanDirectoryRecursively() throws IOException {
        IOUtils.cleanDirectoryRecursively(Paths.get(CommonConstant.RESOURCES_PATH + "/my/my-zip"), -1);
    }

    @Test
    void downloadAndUnzip() throws IOException {
        // 压缩包才可以,不然报错
        IOUtils.downloadAndUnzip("https://www.baidu.com", CommonConstant.RESOURCES_PATH + "/my/my-baidu");
    }

    @Test
    void downloadFile() throws IOException {
        IOUtils.downloadFile("https://www.baidu.com", Paths.get(CommonConstant.RESOURCES_PATH + "/my/my-downloadFile.txt"));
    }

    @Test
    void downloadAndExtract() throws IOException {
        // 压缩包才可以
        IOUtils.downloadAndExtract("https://www.baidu.com", Paths.get(CommonConstant.RESOURCES_PATH + "/my/my-downloadAndExtract"));
    }

    @Test
    void testDownloadAndUnzip() throws IOException {
        // 压缩包才可以,不然报错
        IOUtils.downloadAndUnzip("https://www.baidu.com", Paths.get(CommonConstant.RESOURCES_PATH + "/my/my-testDownloadAndUnzip"));
    }

    @Test
    void testDownloadFile() throws IOException {
        IOUtils.downloadFile("https://www.baidu.com", CommonConstant.RESOURCES_PATH + "/my", "testDownloadFile.html");
    }

    @Test
    void extract() throws IOException {
        IOUtils.extract(CommonConstant.RESOURCES_PATH + "/my/my-extract.zip", CommonConstant.RESOURCES_PATH + "/my/my-extract");
    }

    @Test
    void testDownloadAndExtract() throws IOException {
        // 压缩包才可以
        IOUtils.downloadAndExtract("https://www.baidu.com", CommonConstant.RESOURCES_PATH + "/my/my-downloadAndExtract-");
    }

    @Test
    void listDisks() {
        List<String> list = IOUtils.listDisks();
        if (!list.isEmpty()) {
            list.forEach(System.out::println);
        }
    }

    @Test
    void downloadByteArray() throws Exception {
        // 创建一个Mock HttpServletResponse对象
        HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
        // 创建一个StringWriter来存储响应内容
        // 使用PrintWriter将内容输出到StringWriter
        // 设置响应状态码
        // 设置响应内容类型
        // 设置响应内容长度
        // 获取响应输出流,并将内容写入其中
        IOUtils.downloadByteArray(response, IOUtils.toByteArray("a1.txt"), "downloadByteArray.txt");
    }


    @Test
    void mkdirsmy() throws IOException {
        IOUtils.mkdirs(CommonConstant.RESOURCES_PATH + File.separator + "my/mkdirsmy", "test");
    }

    @Test
    void getHtmlPicture() {
        IOUtils.getHtmlPicture("https://android-screenimgs.25pp.com/fs08/2020/06/24/0/110_bc41714609e839c721dd938a78e64c81.png", CommonConstant.RESOURCES_PATH + File.separator + "my/tempImg", "test.png");
    }

    @Test
    void getFilesize() {
        System.out.println(IOUtils.getFilesize("a1.txt"));
    }

    @Test
    void createDir() {
        IOUtils.createDir(CommonConstant.RESOURCES_PATH + File.separator + "my/my-baidu");
    }

    @Test
    void delFile() {
        IOUtils.delFile(CommonConstant.RESOURCES_PATH + File.separator + "my/my-baidu");
    }

    @Test
    void toByteArray() throws IOException {
        System.out.println(Arrays.toString(IOUtils.toByteArray("a1.txt")));
    }

    @Test
    void toByteBuffer() throws IOException {
        System.out.println(IOUtils.toByteBuffer("a1.txt"));
    }

    @Test
    void copy() throws IOException {
        IOUtils.copy("a1.txt");
    }

    @Test
    void readFileByBytes() throws IOException {
        System.out.println(Arrays.toString(IOUtils.readFileByBytes("a1.txt")));
    }

    @Test
    void inputStream2Str() throws IOException {
        System.out.println(IOUtils.inputStream2Str(IOUtils.str2InputStream("字符串666")));
    }

    @Test
    void inputStream2StrByApacheCommons() throws IOException {
        System.out.println(IOUtils.inputStream2StrByApacheCommons(IOUtils.str2InputStream("字符串666")));
    }

    @Test
    void str2InputStream() {
        System.out.println(IOUtils.str2InputStream("字符串666"));
    }

    @Test
    void str2InputStreamByApacheCommons() throws IOException {
        System.out.println(IOUtils.str2InputStreamByApacheCommons("字符串666"));
    }

    @Test
    void str2InputStreamByGoogleGuava() throws IOException {
        System.out.println(IOUtils.str2InputStreamByGoogleGuava("字符串666"));
    }

    @Test
    void getClasspathFilePath() {
        System.out.println(IOUtils.getClasspathFilePath("a1.txt"));
    }

    @Test
    void getResourceLoader() {
        System.out.println(IOUtils.getResourceLoader());
    }

    @Test
    void getClassLoader() {
        System.out.println(IOUtils.getClassLoader());
    }

    @Test
    void getSpringResource() {
        System.out.println(IOUtils.getSpringResource("a1.txt"));
    }

    @Test
    void getResourceFileStream() throws IOException {
        System.out.println(IOUtils.getResourceFileStream("a1.txt"));
    }
}

你可能感兴趣的:(记录,常用工具,Java,java)