在我们日常开发过程中会经常遇到通过模板生成文件的业务场景,但是模板可能会经常发生改变,所以我们使用以下代码实现对文件的读取:
private static List<String> loadFiles(String basePath, String fileType, List<String> lst) {
URL resource = FileUitls.class.getClassLoader().getResource(basePath);
if (resource == null) {
return lst;
}
File file = new File(resource.getFile());
if (file.isDirectory()) {
// 如果当前文件是文件夹 那么获取下面所有的文件
String[] list = file.list();
for (String s : list) {
loadFiles(basePath + "/" + s, fileType, lst);
}
} else if (file.isFile()) {
if (isEmpty(fileType) || basePath.endsWith("." + fileType)) {
lst.add(basePath);
}
}
return lst;
}
但是当我们将写好的程序打成jar包提供给其它程序使用之后会发现,原本开发环境可以正常读取的文件都会消失,导致这个问题的原因是操作系统会将jar看作是一个文件 而不是一个目录结构,那么如果我们再通过new file的形式去读取jar内的肯定会出现问题。正确的姿势如下:
public class FileUitls{
/**
*读取指定文件夹下的指定类型的文件
* @param basePath 基础目录
* @param fileType 文件类型
* @param lst 存放目录的容器
*/
public static List<String> loadFiles(String basePath, String fileType, List<String> lst) {
URL resource = FileUitls.class.getClassLoader().getResource(basePath);
if (resource == null) {
return lst;
}
if ("jar".equals(resource.getProtocol())) {
//jar包读取
loadFilesInJar(basePath, fileType, lst);
} else {
File file = new File(resource.getFile());
if (file.isDirectory()) {
// 如果当前文件是文件夹 那么获取下面所有的文件
String[] list = file.list();
for (String s : list) {
loadFiles(basePath + "/" + s, fileType, lst);
}
} else if (file.isFile()) {
if (isEmpty(fileType) || basePath.endsWith("." + fileType)) {
lst.add(basePath);
}
}
}
return lst;
}
// 读取jar内的文件夹信息
public static List<String> loadFilesInJar(String basePath, String fileType, List<String> lst) {
try {
ClassLoader classLoader = FileUitls.class.getClassLoader();
URL url = classLoader.getResource(basePath);
String urlStr = url.toString();
// 找到!/ 截断之前的字符串
String jarPath = urlStr.substring(0, urlStr.indexOf("!/") + 2);
URL jarURL = new URL(jarPath);
JarURLConnection jarCon = (JarURLConnection) jarURL.openConnection();
JarFile jarFile = jarCon.getJarFile();
Enumeration<JarEntry> jarEntrys = jarFile.entries();
while (jarEntrys.hasMoreElements()) {
JarEntry entry = jarEntrys.nextElement();
// 简单的判断路径,如果想做到像Spring,Ant-Style格式的路径匹配需要用到正则。
String name = entry.getName();
if (name.startsWith(basePath) && !name.equals(basePath)) {
if (entry.isDirectory()) {
// 文件夹 迭代
loadFilesInJar(name, fileType, lst);
} else if (!lst.contains(name)) {
if (isEmpty(fileType) || name.endsWith("." + fileType)) {
lst.add(name);
}
}
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return lst;
}
// 读取指定文件信息
public static String loadFile(String fileName) {
URL resource = FileUitls.class.getClassLoader().getResource(fileName);
if (resource == null) {
return "";
}
// 如果文件是jar 那么需要用jar的方式读取
if ("jar".equals(resource.getProtocol())) {
//jar包读取
return loadJarFile(fileName);
} else {
StringBuilder content = new StringBuilder();
FileInputStream fr = null;
try {
fr =new FileInputStream(resource.getFile());
byte[] bytes = new byte[1024];
int len = 0;
while ((len = fr.read(bytes)) > 0) {
content.append(new String(bytes, 0, len, StandardCharsets.UTF_8));
}
} catch (IOException e) {
e.printStackTrace();
}finally {
closeIO(fr);
}
return content.toString();
}
}
// 读取jar包内的文件信息
public static String loadJarFile(String fileName) {
StringBuilder content = new StringBuilder();
InputStream fr = FileUitls.class.getClassLoader().getResourceAsStream(fileName);
try {
byte[] bytes = new byte[1024];
int len = 0;
while ((len = fr.read(bytes)) > 0) {
content.append(new String(bytes, 0, len, StandardCharsets.UTF_8));
}
} catch (IOException e) {
e.printStackTrace();
}finally {
closeIO(fr);
}
return content.toString();
}
}