package com.guanghua.brick.util;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.jar.JarFile;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* @author leeon
* 对类路径上的文件或者文件系统上的文件进行搜索的工具类
*/
public class FileUtil {
private static Log logger = LogFactory.getLog(FileUtil.class);
/**
* 在文件系统的某个目录中搜索符合pattern要求的文件,filePath就是搜索的目录的全路径
* 比如filePath路径是c:/foo/bar,那么就是搜索c:/foo/bar下的所有符合patter格式的文件
* 如果filePath的不是目录或者不存在,那么返回一个空列表。
* @param filePath 需要搜索的目录路径
* @param pattern 文件名(不包括文件路径)符合的模版,正则表达式的模版
* @return 返回搜索到的文件全路径列表
*/
public static List<String> searchFileFromFolder(String filePath,
String pattern) {
return searchFileFromFolder(getFileResource(filePath), pattern,
null);
}
/**
* 检查文件系统某个目录下所有名字(非路径,只包括文件名)符合正则表达式pattern要求的文件
* 返回的结果是一个String的列表,可以有两种结果
* 如果prefix为null,列表里的字符串就是符合要求的文件的绝对路径
* 如果prefix不为null,列表里的字符串就是类路径格式的字符串,比如在c:/foo/bar下搜索,prefix为foo1/bar1
* 搜索到一个文件是c:/foo/bar/test/Test.class,那么返回的list中的字符串就是foo1/bar1/test/Test.class
* 如果prefix传的是"",那么返回的字符串就是/test/Test.class
* @param folder, 开始搜索的文件夹,如果文件夹为空,或者不存在,或者不是文件夹,那么返回空列表
* @param pattern, 搜索用的正则表达式
* @param prefix, 返回类路径或者是文件绝对路径的标志,如果是null,返回文件绝对路径
* @return 返回list,符合list要求的每一个对象是该文件的绝对路径
*/
public static List<String> searchFileFromFolder(File folder,
final String pattern, String prefix) {
List<String> re = new ArrayList<String>();
//给prefix加上/,以便于递归
if (prefix != null && prefix.length() != 0)
prefix = prefix + "/";
//当文件夹存在,并且是文件夹时,才进行搜索
if (folder.exists() && folder.isDirectory()) {
//获取符合pattern条件的文件列表
File[] files = folder.listFiles(new FileFilter() {
public boolean accept(File file) {
//如果该文件是隐藏的,不继续寻找
if (file.isHidden())
return false;
else {
//如果该文件是目录那么继续寻找他的儿子
if (file.isDirectory())
return true;
else {
//如果不是目录,则检验其文件名是否满足要求
return Pattern.matches(pattern, file
.getName());
}
}
}
});
//遍历文件列表,看是否是目录或者文件,是目录就递归,是文件就根据prefix返回
for (int i = 0; files != null && i < files.length; i++) {
if (files[i].isDirectory()) {
re.addAll(searchFileFromFolder(files[i], pattern,
prefix == null ? null : prefix
+ files[i].getName()));
} else {
//需要返回文件路径
if (prefix == null)
re.add(files[i].getAbsolutePath());
//需要返回类路径
else
re.add(prefix + files[i].getName());
}
}
}
return re;
}
/**
* 检查zip包中某个目录下的所有文件名(不包括文件路径)符合正则表达式pattern要求的文件
* 返回一个文件类路径的列表.
* folderPath是搜索的zip包中的类路径文件夹,prefix是一个其实搜索和返回路径的前缀,主要用于搜索war包时
* 比如一个war包,foo.war,那么zipFile时foo.war的ZipFile,要搜索pattern为*.hbm.xml,搜索的类路径就是com/guanghua/domain,而搜索的前缀就应该是/WEB-INF/classes
* 这时候,真正开始搜索的zip包路径是/WEB-INF/classes/com/guanghua/domain,而返回的文件类路径却是com/guanghua/domain/Test.hbm.xml的形式,返回结果会自动截取前缀
* 同样在搜索ear包时,也同理可以这样做。搜索jar包的化,prefix传入""即可
* @param zipFile 被搜索的zip文件
* @param pattern 文件名必须符合的正则表达式的pattern
* @param folderPath
* @param prefix
* @return zip文件夹中所有符合条件的文件的类路径列表
*/
public static List<String> searchFileFromZip(ZipFile zipFile,
String pattern, String folderPath, String prefix) {
List<String> list = new ArrayList<String>();
//拿到zip中所有的entry
Enumeration e = zipFile.entries();
folderPath = folderPath.startsWith("/") ? prefix + folderPath
: prefix + "/" + folderPath;
while (e.hasMoreElements()) {
ZipEntry zipEntry = (ZipEntry) e.nextElement();
//获取zip中文件的路径
String zip = zipEntry.getName();
zip = zip.startsWith("/") ? zip : "/" + zip;
//如果zipEntry的开头是prefix,那么说明这是prefix目录下的一个文件
if (!zipEntry.isDirectory() && zip.startsWith(folderPath)) {
//获取真实的文件名
String jarFileName = zip
.substring(zip.lastIndexOf("/") + 1);
//文件名符合pattern的要求
if (Pattern.matches(pattern, jarFileName))
list.add(zip.substring(prefix.length() + 1));
}
}
return list;
}
/**
* 在指定的类路径中搜索文件名符合pattern要求的文件
* 比如要搜索com/guanghua/brick下所有符合.hbm.xml结尾的文件就可以使用该方法
* 返回的结果是符合要求的文件的类路径,比如com/guanghua/brick/domain/foo.hbm.xml
* @param classPath 指定的类路径
* @param pattern 文件名必须符合的pattern
* @return 返回在指定类路径中文件名符合要求的类路径列表
* @throws Exception
*/
public static List<String> searchFileFromClassPath(
String classPath, String pattern) throws IOException {
//获取指定的类路径的定位URL
URL[] urls = BeanUtil.getClassPathFileURLs(classPath);
//返回的是list,但是利用set来保证没有重复的url
List<String> list = new ArrayList<String>();
Set<String> set = new HashSet<String>();
//没有找到对应的url list,返回空
if (urls == null)
return list;
for (int i = 0; i < urls.length; i++) {
//将搜索到的结果放入set
set.addAll(searchFileFromClassPath(urls[i], classPath,
pattern));
}
list.addAll(set);
return list;
}
/**
* 根据URL确定搜索文件的路径,然后根据classPath确定搜索的类路径,再搜索文件名符合pattern格式的文件
* classPath所在的位置可能是jar,可能是war,可能是folder,但必须和url的位置一致。
* 在类路径中搜索符合pattern要求的文件
* @param url 搜索的jar包或者文件夹所在的url路径,
* @param classPath 搜索的类路径
* @param pattern 文件名符合的模版
* @return 返回在指定类路径中文件名符合要求的类路径列表
* @throws IOException
*/
public static List<String> searchFileFromClassPath(URL url,
String classPath, String pattern) throws IOException {
logger.debug("search file type: [" + pattern + "]");
logger.debug("search file in classpath: [" + classPath + "]");
logger.debug("the real filepath is : [" + url + "]");
if (url == null)
return new ArrayList<String>();
//处理文件名
String file = url.getFile();
int i = file.indexOf("!");
file = (i != -1) ? file.substring(0, i) : file;
//获取协议
String protocol = url.getProtocol();
//如果类所在的文件路径是jar包
if ("jar".equals(protocol)) {
JarURLConnection jc = (JarURLConnection) url
.openConnection();
logger.debug("search jar file from :[" + url + "]");
return searchFileFromZip(jc.getJarFile(), pattern,
classPath, "");
//如果类所在的文件路径是wsjar包
} else if ("wsjar".equals(protocol)) {
//wsjar需要去掉file:/才能在ws下识别
if (file.startsWith("file:/"))
file = file.substring(6);
logger.debug("search wsjar file from :[" + file + "]");
JarFile jarFile = new JarFile(new File(URLDecoder.decode(
file, "UTF-8")));
return searchFileFromZip(jarFile, pattern, classPath, "");
//如果类所在的文件路径是zip包
} else if ("zip".equals(protocol)) {
//如果类所在的文件路径是war包
if (file.endsWith("war")) {
logger.debug("search war file from :[" + file + "]");
ZipFile zipFile = new ZipFile(new File(URLDecoder
.decode(file, "UTF-8")));
return searchFileFromZip(zipFile, pattern, classPath,
"/WEB-INF/classes");
//如果类所在的文件路径是普通zip包
} else {
logger.debug("search zip file from :[" + file + "]");
ZipFile zipFile = new ZipFile(new File(URLDecoder
.decode(file, "UTF-8")));
return searchFileFromZip(zipFile, pattern, classPath,
"");
}
//如果是普通的文件协议
} else if ("file".equals(protocol)) {
logger
.debug("search filesystem folder from :[" + url
+ "]");
return searchFileFromFolder(new File(URLDecoder.decode(url
.getFile(), "UTF-8")), pattern, classPath);
//其余情况返回空列表
} else
return new ArrayList<String>();
}
/**
* 根据传入文件完整路径,获取文件所在的文件夹路径
* 原理是截取最后一个"/"之前的字符串作为文件夹名称
* @param filePath 文件完整路径
* @return 文件夹名称
*/
public static String getFloderName(String filePath) {
return filePath.substring(0, filePath.lastIndexOf("/"));
}
/**
* 根据传入的文件完整路径,获取文件的名称
* 原理是截取最后一个"/"之后的字符串作为文件名
* @param filePath 文件完整路径
* @return 文件名
*/
public static String getFileName(String filePath) {
return filePath.substring(filePath.lastIndexOf("/") + 1);
}
/**
* 根据文件路径(绝对路径)直接返回文件对象。
* 相当于new File(filePath)
* @param filePath 文件的绝对路径
* @return 文件对象
*/
public static File getFileResource(String filePath) {
return new File(filePath);
}
}
Java代码片段
最新推荐文章于 2021-08-15 17:25:20 发布