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"));
}
}