1.思路
通过给定的包名,获取到该资源路径,然后判断该路径是文件夹还是jar包。
如果是文件夹,直接通过 File.listFile() 方法获取所有文件,然后找到类文件。
如果是 jar 包的话,则通过 jarInputStream 构造 jarEntry 获取文件。
2.代码
package com.example.demo;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
/**
* @author 相柳
* @date 2021/7/7
*/
public class Main {
/**
* 扫描指定路径下的类文件
*
* @param packagePath 包路径
* @return Set<String>
*/
public static Set<String> scan(String packagePath) {
// 转化包路径为文件路径
String scanPath = packagePath.replace(".", "/");
// 扫描
ClassLoader classLoader = Main.class.getClassLoader();
URL resource = classLoader.getResource(scanPath);
Set<String> fileNameSet = new LinkedHashSet<>();
if (resource == null) {
throw new RuntimeException("资源不存在:" + packagePath);
}
String rootPath = getRootPath(resource);
if (isJarFile(resource.getFile())) {
try {
// 是jar包使用JarInputStream
JarInputStream jarInputStream = new JarInputStream(new FileInputStream(rootPath));
JarEntry nextJarEntry = jarInputStream.getNextJarEntry();
// 遍历
while (null != nextJarEntry) {
String name = nextJarEntry.getName();
// 如果是指定包名下的文件并且是.class结尾,那就保存它
if (name.startsWith(scanPath) && isClassFile(name)) {
fileNameSet.add(name.replace(".class", ""));
}
nextJarEntry = jarInputStream.getNextJarEntry();
}
} catch (IOException e) {
e.printStackTrace();
}
} else {
// 是文件夹,获取该文件夹下所有文件
Set<String> allFilePath = getAllFilePath(rootPath);
for (String filePath : allFilePath) {
fileNameSet.add(transFilePathToPackagePath(filePath, scanPath));
}
}
return fileNameSet;
}
/**
* 遍历获取某个文件下所有文件名称
*
* @param path path
* @return Set<String>
*/
private static Set<String> getAllFilePath(String path) {
Set<String> fileSet = new LinkedHashSet<>();
File file = new File(path);
return getAllFilePath(fileSet, file);
}
/**
* 递归遍历获取某个文件下所有文件名称
*
* @param fileSet fileSet
* @param file 源文件
* @return Set<String>
*/
private static Set<String> getAllFilePath(Set<String> fileSet, File file) {
if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null) {
for (File file1 : files) {
getAllFilePath(fileSet, file1);
}
}
} else {
if (isClassFile(file.getAbsolutePath())) {
fileSet.add(file.getAbsolutePath());
}
return fileSet;
}
return fileSet;
}
/**
* 把文件路径转为包路径
*
* @param filePath filePath
* @param scanPath 扫描路径
* @return String
*/
private static String transFilePathToPackagePath(String filePath, String scanPath) {
filePath = filePath.replace("\\", "/");
String substring = filePath.substring(filePath.indexOf(scanPath), filePath.indexOf(".class"));
return substring.replace("\\", ".").replace("/", ".");
}
/**
* 判断一个文件是不是jar包
*
* @param fileName fileName
* @return true-是,false-否
*/
private static boolean isJarFile(String fileName) {
return fileName.contains(".jar!");
}
/**
* 判断一个文件class文件
*
* @param fileName fileName
* @return true-是,false-否
*/
private static boolean isClassFile(String fileName) {
return fileName.endsWith(".class");
}
/**
* 获取文件路径
*
* @param url url
* @return String
*/
private static String getRootPath(URL url) {
String path = url.getFile();
if (path.contains("!")) {
return path.substring(5, path.indexOf("!"));
}
return path;
}
}