SpringBoot jar 中读取 resource 下的目录
读取目录下的文件列表
ResourceListUtil.listResourceDirFiles("view_node"),为读取 resource 目录下的 view_node 目录下的文件列表
@Slf4j
public class ResourceListUtil {
/**
* 修复版:列出 resource 下指定目录的所有文件(适配 Jar 包/开发环境)
* 解决 view_node 目录在 Jar 包中无法读取文件的问题
*
* @param dirPath resource 下的目录路径,例如:view_node、config/
* @return 文件的相对路径列表(如 view_node/test.txt、view_node/sub/file.json)
*/
public static List<String> listResourceDirFiles(String dirPath) {
List<String> fileList = new ArrayList<>();
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
// 1. 统一路径格式:确保目录以 / 结尾,匹配规则包含所有子级
String normalizedDir = StrUtil.addSuffixIfNot(dirPath, "/");
String pattern = "classpath:" + normalizedDir + "**";
try {
Resource[] resources = resolver.getResources(pattern);
for (Resource resource : resources) {
// 2. 关键修复:不再依赖 isFile(),而是通过路径判断是否为文件(排除目录)
String resourceUrl = resource.getURL().toString();
String relativePath = extractRelativePath(resourceUrl);
// 3. 过滤条件:
// - 路径非空
// - 属于目标目录(view_node)
// - 不是目录(通过是否包含文件后缀/不含末尾/ 判断)
if (StrUtil.isNotBlank(relativePath)
&& relativePath.startsWith(normalizedDir)
&& !relativePath.endsWith("/") // 排除目录
&& StrUtil.contains(relativePath, ".")) { // 确保是文件(有后缀)
fileList.add(relativePath);
}
}
} catch (IOException e) {
log.error("资源获取异常", e);
}
return fileList;
}
/**
* 辅助方法:从资源 URL 中提取 resource 根目录下的相对路径
* 兼容 Jar 包(jar:file:/xxx.jar!/BOOT-INF/classes!/view_node/test.txt)
* 和开发环境(file:/xxx/target/classes/view_node/test.txt)
* <p>
* jar:nested:/D:/javaProject/company/xingtu-tygkpt/xingtu-tygkpt-application/target/application.jar/!BOOT-INF/classes/!/view_node/9_8396788870686588991.txt
*
* @param resourceUrl 资源的完整 URL
* @return 相对路径(如 view_node/test.txt)
*/
private static String extractRelativePath(String resourceUrl) {
// Jar 包内路径特征:!/BOOT-INF/classes!/ (AI生成的判断)
String jarMarker = "!/BOOT-INF/classes!/";
// SpringBoot 的 Jar 包内路径特征
String jarMarker2 = "/!BOOT-INF/classes/!/";
// 开发环境路径特征:/target/classes/
String devMarker = "/target/classes/";
String relativePath = null;
if (resourceUrl.contains(jarMarker)) {
// Jar 包环境:截取 BOOT-INF/classes! 后的部分
relativePath = StrUtil.subAfter(resourceUrl, jarMarker, false);
} else if (resourceUrl.contains(jarMarker2)) {
relativePath = StrUtil.subAfter(resourceUrl, jarMarker2, false);
} else if (resourceUrl.contains(devMarker)) {
// 开发环境:截取 target/classes/ 后的部分
relativePath = StrUtil.subAfter(resourceUrl, devMarker, false);
}
// 处理编码问题(如路径中的空格、特殊字符)
if (StrUtil.isNotBlank(relativePath)) {
return relativePath;
}
return null;
}
/**
* 扩展:仅列出指定目录下的一级文件(不包含子目录里的文件)
*
* @param dirPath 目标目录(如 view_node)
* @return 一级文件列表
*/
public static List<String> listFirstLevelFiles(String dirPath) {
List<String> allFiles = listResourceDirFiles(dirPath);
List<String> firstLevelFiles = new ArrayList<>();
String normalizedDir = StrUtil.addSuffixIfNot(dirPath, "/");
for (String file : allFiles) {
// 一级文件:路径中仅包含目标目录的一个 /,无更多子目录
String subPath = StrUtil.subAfter(file, normalizedDir, false);
if (!StrUtil.contains(subPath, "/")) {
firstLevelFiles.add(file);
}
}
return firstLevelFiles;
}
}
2. 读取压缩文件并解压缩
以 tar.gz 文件为例,可问 AI,我这也差不多是 ai 的逻辑,解压对应文件到内存,主要是我这 view_node 下的文件有点多,压缩起来比较小,也基本上不会改里面的内容
/**
* 解析处理节点数据
*/
private void extractViewNode() throws Exception {
Map<String, byte[]> stringMap = unzipTarGzFromJarToMemory("view_node.tar.gz");
TEST_NODE_MAP.putAll(stringMap);
}
/**
* tar.gz 解压数据到内存
*
* @param path resource path 路径
* @return key 为路径,value 为内容字节数组
*/
public static Map<String, byte[]> unzipTarGzFromJarToMemory(String path) throws Exception {
Map<String, byte[]> fileMap = new HashMap<>();
// 1. 流式解压:GZIP -> TAR -> 内存
try (InputStream inputStream = ResourceUtil.getStream(path);
// 先解压GZIP层
GzipCompressorInputStream gzipInputStream = new GzipCompressorInputStream(inputStream);
// 再读取TAR层
TarArchiveInputStream tarInputStream = new TarArchiveInputStream(gzipInputStream)) {
TarArchiveEntry entry;
byte[] buffer = new byte[8192];
// 2. 遍历TAR中的每一个文件
while ((entry = tarInputStream.getNextEntry()) != null) {
if (entry.isDirectory()) {
continue;
}
// 3. 将当前文件内容读取到字节数组
try (ByteArrayOutputStream baos = new ByteArrayOutputStream((int) entry.getSize())) {
int len;
while ((len = tarInputStream.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
fileMap.put(entry.getName(), baos.toByteArray());
}
}
}
return fileMap;
}

浙公网安备 33010602011771号