#525 1.增加通配符匹配,对字符串可用通配符匹配,2.文件搜索可用AntPath,通配符,正则表达式匹配 3.FilePathUtils增加在windows下,将路径转为windows路径
This commit is contained in:
@@ -17,6 +17,8 @@ public abstract class Platforms {
|
||||
// 文件路径分隔符
|
||||
public static final String FILE_PATH_SEPARATOR = File.separator;
|
||||
public static final char FILE_PATH_SEPARATOR_CHAR = File.separatorChar;
|
||||
public static final char WINDOWS_FILE_PATH_SEPARATOR_CHAR='\\';
|
||||
public static final char LINUX_FILE_PATH_SEPARATOR_CHAR='/';
|
||||
|
||||
// ClassPath分隔符
|
||||
public static final String CLASS_PATH_SEPARATOR = File.pathSeparator;
|
||||
|
||||
@@ -71,7 +71,8 @@ public abstract class MapUtil {
|
||||
*
|
||||
* @see org.apache.commons.lang3.concurrent.ConcurrentUtils#putIfAbsent(ConcurrentMap, Object, Object)
|
||||
*/
|
||||
public static <K, V> V putIfAbsentWithFinalValue(final ConcurrentMap<K, V> map, final K key, final V value) {
|
||||
public static <K, V> V putIfAbsentWithFinalValue(@NotNull final ConcurrentMap<K, V> map, final K key,
|
||||
final V value) {
|
||||
final V result = map.putIfAbsent(key, value);
|
||||
return result != null ? result : value;
|
||||
}
|
||||
@@ -84,12 +85,8 @@ public abstract class MapUtil {
|
||||
* @see org.apache.commons.lang3.concurrent.ConcurrentUtils#createIfAbsent(ConcurrentMap, Object,
|
||||
* org.apache.commons.lang3.concurrent.ConcurrentInitializer)
|
||||
*/
|
||||
public static <K, V> V createIfAbsent(final ConcurrentMap<K, V> map, final K key,
|
||||
final ValueCreator<? extends V> creator) {
|
||||
if (map == null || creator == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static <K, V> V createIfAbsent(@NotNull final ConcurrentMap<K, V> map, final K key,
|
||||
@NotNull final ValueCreator<? extends V> creator) {
|
||||
final V value = map.get(key);
|
||||
if (value == null) {
|
||||
return putIfAbsentWithFinalValue(map, key, creator.get());
|
||||
@@ -100,8 +97,6 @@ public abstract class MapUtil {
|
||||
/**
|
||||
* 创建Value值的回调函数
|
||||
*
|
||||
* from Common Lang
|
||||
*
|
||||
* @see MapUtil#createIfAbsent(ConcurrentMap, Object, ValueCreator)
|
||||
*/
|
||||
public interface ValueCreator<T> {
|
||||
@@ -212,7 +207,7 @@ public abstract class MapUtil {
|
||||
/**
|
||||
* 相比HashMap,当key是枚举类时, 性能与空间占用俱佳.
|
||||
*/
|
||||
public static <K extends Enum<K>, V> EnumMap<K, V> newEnumMap(Class<K> type) {
|
||||
public static <K extends Enum<K>, V> EnumMap<K, V> newEnumMap(@NotNull Class<K> type) {
|
||||
return new EnumMap<K, V>(Preconditions.checkNotNull(type));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,49 +1,36 @@
|
||||
package org.springside.modules.utils.io;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springside.modules.utils.base.Platforms;
|
||||
import org.springside.modules.utils.base.annotation.NotNull;
|
||||
import org.springside.modules.utils.text.MoreStringUtil;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
|
||||
/**
|
||||
* 关于文件名,文件路径的工具集
|
||||
* 关于文件路径的工具集
|
||||
*
|
||||
* @author calvin
|
||||
*/
|
||||
public abstract class FilePathUtil {
|
||||
|
||||
/**
|
||||
* 获取文件名(不包含路径)
|
||||
* 在Windows环境里,兼容Windows上的路径分割符,将 '/' 转回 '\'
|
||||
*/
|
||||
public static String getFileName(@NotNull String fullName) {
|
||||
Validate.notEmpty(fullName);
|
||||
int last = fullName.lastIndexOf(Platforms.FILE_PATH_SEPARATOR_CHAR);
|
||||
return fullName.substring(last + 1);
|
||||
}
|
||||
public static String normalizePath(String path) {
|
||||
if (Platforms.FILE_PATH_SEPARATOR_CHAR == Platforms.WINDOWS_FILE_PATH_SEPARATOR_CHAR
|
||||
&& StringUtils.indexOf(path, Platforms.LINUX_FILE_PATH_SEPARATOR_CHAR) != -1) {
|
||||
return StringUtils.replaceChars(path, Platforms.LINUX_FILE_PATH_SEPARATOR_CHAR,
|
||||
Platforms.WINDOWS_FILE_PATH_SEPARATOR_CHAR);
|
||||
}
|
||||
return path;
|
||||
|
||||
/**
|
||||
* 获取文件名的扩展名部分(不包含.)
|
||||
*/
|
||||
public static String getFileExtension(File file) {
|
||||
return Files.getFileExtension(file.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件名的扩展名部分(不包含.)
|
||||
*/
|
||||
public static String getFileExtension(String fullName) {
|
||||
return Files.getFileExtension(fullName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将路径整理,如 "a/../b",整理成 "b"
|
||||
*/
|
||||
public static String simplifyPath(String pathName) {
|
||||
return Files.simplifyPath(pathName);
|
||||
public static String simplifyPath(String path) {
|
||||
return Files.simplifyPath(path);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,4 +63,5 @@ public abstract class FilePathUtil {
|
||||
public static String getJarPath(Class<?> clazz) {
|
||||
return clazz.getProtectionDomain().getCodeSource().getLocation().getFile();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
package org.springside.modules.utils.io;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springside.modules.utils.text.WildcardMatcher;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.TreeTraverser;
|
||||
import com.google.common.io.Files;
|
||||
|
||||
public class FileTreeWalker {
|
||||
|
||||
/**
|
||||
* 前序递归列出所有文件, 包含文件与目录,及根目录本身.
|
||||
*
|
||||
* 前序即先列出父目录,在列出子目录. 如要后序遍历, 直接使用Files.fileTreeTraverser()
|
||||
*/
|
||||
public static List<File> listAll(File rootDir) {
|
||||
return Files.fileTreeTraverser().preOrderTraversal(rootDir).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 前序递归列出所有文件, 只包含文件.
|
||||
*/
|
||||
public static List<File> listFile(File rootDir) {
|
||||
return Files.fileTreeTraverser().preOrderTraversal(rootDir).filter(Files.isFile()).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 前序递归列出所有文件, 列出后缀名匹配的文件. (后缀名不包含.)
|
||||
*/
|
||||
public static List<File> listFileWithExtension(final File rootDir, final String extension) {
|
||||
return Files.fileTreeTraverser().preOrderTraversal(rootDir).filter(new FileExtensionFilter(extension)).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 前序递归列出所有文件, 列出文件名匹配通配符的文件
|
||||
*
|
||||
* 如 ("/a/b/hello.txt", "he*") 将被返回
|
||||
*/
|
||||
public static List<File> listFileWithWildcardFileName(final File rootDir, final String fileNamePattern) {
|
||||
return Files.fileTreeTraverser().preOrderTraversal(rootDir).filter(new WildcardFileNameFilter(fileNamePattern))
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 前序递归列出所有文件, 列出文件名匹配正则表达式的文件
|
||||
*
|
||||
* 如 ("/a/b/hello.txt", "he.*\.text") 将被返回
|
||||
*/
|
||||
public static List<File> listFileWithRegexFileName(final File rootDir, final String regexFileNamePattern) {
|
||||
return Files.fileTreeTraverser().preOrderTraversal(rootDir)
|
||||
.filter(new RegexFileNameFilter(regexFileNamePattern)).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 前序递归列出所有文件, 列出符合ant path风格表达式的文件
|
||||
*
|
||||
* 如 ("/a/b/hello.txt", "he.*\.text") 将被返回
|
||||
*/
|
||||
public static List<File> listFileWithAntPath(final File rootDir, final String antPathPattern) {
|
||||
return Files.fileTreeTraverser().preOrderTraversal(rootDir).filter(new AntPathFilter(antPathPattern)).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接使用Guava的TreeTraverser,获得更大的灵活度, 比如加入各类filter,前序/后序的选择,一边遍历一边操作
|
||||
*
|
||||
* <pre>
|
||||
* FileUtil.fileTreeTraverser().preOrderTraversal(root).iterator();
|
||||
* </pre>
|
||||
*/
|
||||
public static TreeTraverser<File> fileTreeTraverser() {
|
||||
return Files.fileTreeTraverser();
|
||||
}
|
||||
|
||||
/**
|
||||
* 以文件名正则表达式为filter,配合fileTreeTraverser使用
|
||||
*/
|
||||
public static final class RegexFileNameFilter implements Predicate<File> {
|
||||
private final Pattern pattern;
|
||||
|
||||
private RegexFileNameFilter(String pattern) {
|
||||
this.pattern = Pattern.compile(pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(File input) {
|
||||
return input.isFile() && pattern.matcher(input.getName()).matches();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 以文件名通配符为filter,配合fileTreeTraverser使用.
|
||||
*
|
||||
* @param pattern 支持*与?的通配符,如hello*.txt 匹配 helloworld.txt
|
||||
*/
|
||||
public static final class WildcardFileNameFilter implements Predicate<File> {
|
||||
private final String pattern;
|
||||
|
||||
private WildcardFileNameFilter(String pattern) {
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(File input) {
|
||||
return input.isFile() && WildcardMatcher.match(input.getName(), pattern);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 以文件名后缀做filter,配合fileTreeTraverser使用
|
||||
*/
|
||||
public static final class FileExtensionFilter implements Predicate<File> {
|
||||
private final String extension;
|
||||
|
||||
private FileExtensionFilter(String extension) {
|
||||
this.extension = extension;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(File input) {
|
||||
return input.isFile() && extension.equals(FileUtil.getFileExtension(input));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 以ant风格的path为filter,配合fileTreeTraverser使用.
|
||||
*
|
||||
* @param pattern 支持ant风格的通配符,如/var/?/a?.txt 匹配 /var/b/ab.txt, 其他通配符包括**,*
|
||||
*/
|
||||
public static final class AntPathFilter implements Predicate<File> {
|
||||
private final String pattern;
|
||||
|
||||
private AntPathFilter(String pattern) {
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(File input) {
|
||||
return input.isFile() && WildcardMatcher.matchPath(input.getName(), pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,12 +14,11 @@ import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.springside.modules.utils.base.Platforms;
|
||||
import org.springside.modules.utils.base.annotation.NotNull;
|
||||
import org.springside.modules.utils.base.annotation.Nullable;
|
||||
import org.springside.modules.utils.text.Charsets;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.TreeTraverser;
|
||||
import com.google.common.io.Files;
|
||||
|
||||
/**
|
||||
@@ -223,40 +222,6 @@ public abstract class FileUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 前序递归列出所有文件, 包含文件与目录,及根目录本身.
|
||||
*
|
||||
* 前序即先列出父目录,在列出子目录. 如要后序遍历, 直接使用Files.fileTreeTraverser()
|
||||
*/
|
||||
public static List<File> listAll(File rootDir) {
|
||||
return Files.fileTreeTraverser().preOrderTraversal(rootDir).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 前序递归列出所有文件, 只包含文件.
|
||||
*/
|
||||
public static List<File> listFile(File rootDir) {
|
||||
return Files.fileTreeTraverser().preOrderTraversal(rootDir).filter(Files.isFile()).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 前序递归列出所有文件, 只包含后缀名匹配的文件. (后缀名不包含.)
|
||||
*/
|
||||
public static List<File> listFileWithExtension(final File rootDir, final String extension) {
|
||||
return Files.fileTreeTraverser().preOrderTraversal(rootDir).filter(new FileExtensionFilter(extension)).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接使用Guava的TreeTraverser,获得更大的灵活度, 比如加入各类filter,前序/后序的选择,一边遍历一边操作
|
||||
*
|
||||
* <pre>
|
||||
* FileUtil.fileTreeTraverser().preOrderTraversal(root).iterator();
|
||||
* </pre>
|
||||
*/
|
||||
public static TreeTraverser<File> fileTreeTraverser() {
|
||||
return Files.fileTreeTraverser();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断目录是否存在, from Jodd
|
||||
*/
|
||||
@@ -349,18 +314,26 @@ public abstract class FileUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 以文件名后缀做filter,配合fileTreeTraverser使用
|
||||
* 获取文件名(不包含路径)
|
||||
*/
|
||||
public static final class FileExtensionFilter implements Predicate<File> {
|
||||
private final String extension;
|
||||
|
||||
private FileExtensionFilter(String extension) {
|
||||
this.extension = extension;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(File input) {
|
||||
return input.isFile() && extension.equals(FilePathUtil.getFileExtension(input));
|
||||
}
|
||||
public static String getFileName(@NotNull String fullName) {
|
||||
Validate.notEmpty(fullName);
|
||||
int last = fullName.lastIndexOf(Platforms.FILE_PATH_SEPARATOR_CHAR);
|
||||
return fullName.substring(last + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件名的扩展名部分(不包含.)
|
||||
*/
|
||||
public static String getFileExtension(File file) {
|
||||
return Files.getFileExtension(file.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件名的扩展名部分(不包含.)
|
||||
*/
|
||||
public static String getFileExtension(String fullName) {
|
||||
return Files.getFileExtension(fullName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,9 +28,10 @@ import com.google.common.io.Resources;
|
||||
*
|
||||
* 所以resourceName无需以"/"打头即表示jar file中的根目录,带了"/" 反而导致JarFile.getEntry(resouceName)时没有返回.
|
||||
*
|
||||
* 指定contextClass时,class.getResource()会先对name进行处理再交给classLoader,打头的"/"的会被去除,不以"/"打头则表示与该contextClass package的相对路径, 会先转为绝对路径.
|
||||
* 指定contextClass时,class.getResource()会先对name进行处理再交给classLoader,打头的"/"的会被去除,不以"/"打头则表示与该contextClass package的相对路径,
|
||||
* 会先转为绝对路径.
|
||||
*
|
||||
* 3.同名资源
|
||||
* 3.同名资源
|
||||
*
|
||||
* 如果有多个同名资源,除非调用getResources()获取全部资源,否则在URLClassLoader中按ClassPath顺序打开第一个命中的Jar文件.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,268 @@
|
||||
// Copyright (c) 2003-present, Jodd Team (http://jodd.org)
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package org.springside.modules.utils.text;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springside.modules.utils.base.Platforms;
|
||||
|
||||
/**
|
||||
* Checks whether a string or path matches a given wildcard pattern. Possible patterns allow to match single characters
|
||||
* ('?') or any count of characters ('*'). Wildcard characters can be escaped (by an '\'). When matching path, deep tree
|
||||
* wildcard also can be used ('**').
|
||||
* <p>
|
||||
* This method uses recursive matching, as in linux or windows. regexp works the same. This method is very fast,
|
||||
* comparing to similar implementations.
|
||||
*/
|
||||
public class WildcardMatcher {
|
||||
|
||||
/**
|
||||
* Checks whether a string matches a given wildcard pattern.
|
||||
*
|
||||
* @param string input string
|
||||
* @param pattern pattern to match
|
||||
* @return <code>true</code> if string matches the pattern, otherwise <code>false</code>
|
||||
*/
|
||||
public static boolean match(CharSequence string, CharSequence pattern) {
|
||||
return match(string, pattern, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal matching recursive function.
|
||||
*/
|
||||
private static boolean match(CharSequence string, CharSequence pattern, int sNdx, int pNdx) {
|
||||
int pLen = pattern.length();
|
||||
if (pLen == 1) {
|
||||
if (pattern.charAt(0) == '*') { // speed-up
|
||||
return true;
|
||||
}
|
||||
}
|
||||
int sLen = string.length();
|
||||
boolean nextIsNotWildcard = false;
|
||||
|
||||
while (true) {
|
||||
|
||||
// check if end of string and/or pattern occurred
|
||||
if ((sNdx >= sLen)) { // end of string still may have pending '*' in pattern
|
||||
while ((pNdx < pLen) && (pattern.charAt(pNdx) == '*')) {
|
||||
pNdx++;
|
||||
}
|
||||
return pNdx >= pLen;
|
||||
}
|
||||
if (pNdx >= pLen) { // end of pattern, but not end of the string
|
||||
return false;
|
||||
}
|
||||
char p = pattern.charAt(pNdx); // pattern char
|
||||
|
||||
// perform logic
|
||||
if (!nextIsNotWildcard) {
|
||||
|
||||
if (p == '\\') {
|
||||
pNdx++;
|
||||
nextIsNotWildcard = true;
|
||||
continue;
|
||||
}
|
||||
if (p == '?') {
|
||||
sNdx++;
|
||||
pNdx++;
|
||||
continue;
|
||||
}
|
||||
if (p == '*') {
|
||||
char pNext = 0; // next pattern char
|
||||
if (pNdx + 1 < pLen) {
|
||||
pNext = pattern.charAt(pNdx + 1);
|
||||
}
|
||||
if (pNext == '*') { // double '*' have the same effect as one '*'
|
||||
pNdx++;
|
||||
continue;
|
||||
}
|
||||
int i;
|
||||
pNdx++;
|
||||
|
||||
// find recursively if there is any substring from the end of the
|
||||
// line that matches the rest of the pattern !!!
|
||||
for (i = string.length(); i >= sNdx; i--) {
|
||||
if (match(string, pattern, i, pNdx)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
nextIsNotWildcard = false;
|
||||
}
|
||||
|
||||
// check if pattern char and string char are equals
|
||||
if (p != string.charAt(sNdx)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// everything matches for now, continue
|
||||
sNdx++;
|
||||
pNdx++;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- utilities
|
||||
|
||||
/**
|
||||
* Matches string to at least one pattern. Returns index of matched pattern, or <code>-1</code> otherwise.
|
||||
* @see #match(CharSequence, CharSequence)
|
||||
*/
|
||||
public static int matchOne(String src, String[] patterns) {
|
||||
for (int i = 0; i < patterns.length; i++) {
|
||||
if (match(src, patterns[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches path to at least one pattern. Returns index of matched pattern or <code>-1</code> otherwise.
|
||||
* @see #matchPath(String, String)
|
||||
*/
|
||||
public static int matchPathOne(String path, String[] patterns) {
|
||||
for (int i = 0; i < patterns.length; i++) {
|
||||
if (matchPath(path, patterns[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- path
|
||||
|
||||
protected static final String PATH_MATCH = "**";
|
||||
protected static final String PATH_SEPARATORS = "/\\";
|
||||
|
||||
/**
|
||||
* Matches path against pattern using *, ? and ** wildcards. Both path and the pattern are tokenized on path
|
||||
* separators (both \ and /). '**' represents deep tree wildcard, as in Ant.
|
||||
*/
|
||||
public static boolean matchPath(String path, String pattern) {
|
||||
String[] pathElements = StringUtils.split(path, Platforms.FILE_PATH_SEPARATOR_CHAR);
|
||||
String[] patternElements = StringUtils.split(pattern, Platforms.FILE_PATH_SEPARATOR_CHAR);
|
||||
return matchTokens(pathElements, patternElements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Match tokenized string and pattern.
|
||||
*/
|
||||
protected static boolean matchTokens(String[] tokens, String[] patterns) {
|
||||
int patNdxStart = 0;
|
||||
int patNdxEnd = patterns.length - 1;
|
||||
int tokNdxStart = 0;
|
||||
int tokNdxEnd = tokens.length - 1;
|
||||
|
||||
while ((patNdxStart <= patNdxEnd) && (tokNdxStart <= tokNdxEnd)) { // find first **
|
||||
String patDir = patterns[patNdxStart];
|
||||
if (patDir.equals(PATH_MATCH)) {
|
||||
break;
|
||||
}
|
||||
if (!match(tokens[tokNdxStart], patDir)) {
|
||||
return false;
|
||||
}
|
||||
patNdxStart++;
|
||||
tokNdxStart++;
|
||||
}
|
||||
if (tokNdxStart > tokNdxEnd) {
|
||||
for (int i = patNdxStart; i <= patNdxEnd; i++) { // string is finished
|
||||
if (!patterns[i].equals(PATH_MATCH)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (patNdxStart > patNdxEnd) {
|
||||
return false; // string is not finished, but pattern is
|
||||
}
|
||||
|
||||
while ((patNdxStart <= patNdxEnd) && (tokNdxStart <= tokNdxEnd)) { // to the last **
|
||||
String patDir = patterns[patNdxEnd];
|
||||
if (patDir.equals(PATH_MATCH)) {
|
||||
break;
|
||||
}
|
||||
if (!match(tokens[tokNdxEnd], patDir)) {
|
||||
return false;
|
||||
}
|
||||
patNdxEnd--;
|
||||
tokNdxEnd--;
|
||||
}
|
||||
if (tokNdxStart > tokNdxEnd) {
|
||||
for (int i = patNdxStart; i <= patNdxEnd; i++) { // string is finished
|
||||
if (!patterns[i].equals(PATH_MATCH)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
while ((patNdxStart != patNdxEnd) && (tokNdxStart <= tokNdxEnd)) {
|
||||
int patIdxTmp = -1;
|
||||
for (int i = patNdxStart + 1; i <= patNdxEnd; i++) {
|
||||
if (patterns[i].equals(PATH_MATCH)) {
|
||||
patIdxTmp = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (patIdxTmp == patNdxStart + 1) {
|
||||
patNdxStart++; // skip **/** situation
|
||||
continue;
|
||||
}
|
||||
// find the pattern between padIdxStart & padIdxTmp in str between strIdxStart & strIdxEnd
|
||||
int patLength = (patIdxTmp - patNdxStart - 1);
|
||||
int strLength = (tokNdxEnd - tokNdxStart + 1);
|
||||
int ndx = -1;
|
||||
strLoop: for (int i = 0; i <= strLength - patLength; i++) {
|
||||
for (int j = 0; j < patLength; j++) {
|
||||
String subPat = patterns[patNdxStart + j + 1];
|
||||
String subStr = tokens[tokNdxStart + i + j];
|
||||
if (!match(subStr, subPat)) {
|
||||
continue strLoop;
|
||||
}
|
||||
}
|
||||
|
||||
ndx = tokNdxStart + i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ndx == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
patNdxStart = patIdxTmp;
|
||||
tokNdxStart = ndx + patLength;
|
||||
}
|
||||
|
||||
for (int i = patNdxStart; i <= patNdxEnd; i++) {
|
||||
if (!patterns[i].equals(PATH_MATCH)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -108,10 +108,117 @@ public class MapUtilTest {
|
||||
} catch (Throwable t) {
|
||||
assertThat(t).isInstanceOf(UnsupportedOperationException.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void weakMap() {
|
||||
ConcurrentMap<MyBean, MyBean> weakKeyMap = MapUtil.createWeakKeyConcurrentHashMap(10, 1);
|
||||
initExpireAllMap(weakKeyMap);
|
||||
System.gc();
|
||||
assertThat(weakKeyMap.get(new MyBean("A"))).isNull();
|
||||
assertThat(weakKeyMap).hasSize(1); // key仍然在
|
||||
|
||||
ConcurrentMap<MyBean, MyBean> weakKeyMap2 = MapUtil.createWeakKeyConcurrentHashMap(10, 1);
|
||||
MyBean value = new MyBean("B");
|
||||
initExpireKeyMap(weakKeyMap2, value);
|
||||
System.gc();
|
||||
assertThat(weakKeyMap2.get(new MyBean("A"))).isNull();
|
||||
|
||||
ConcurrentMap<MyBean, MyBean> weakKeyMap3 = MapUtil.createWeakKeyConcurrentHashMap(10, 1);
|
||||
MyBean key = new MyBean("A");
|
||||
initExpireValueMap(weakKeyMap3, key);
|
||||
System.gc();
|
||||
assertThat(weakKeyMap3.get(key)).isEqualTo(new MyBean("B"));
|
||||
|
||||
// weak value
|
||||
ConcurrentMap<MyBean, MyBean> weakValueMap = MapUtil.createWeakValueConcurrentHashMap(10, 1);
|
||||
initExpireAllMap(weakValueMap);
|
||||
System.gc();
|
||||
assertThat(weakValueMap.get(new MyBean("A"))).isNull();
|
||||
|
||||
ConcurrentMap<MyBean, MyBean> weakValueMap2 = MapUtil.createWeakValueConcurrentHashMap(10, 1);
|
||||
MyBean value2 = new MyBean("B");
|
||||
initExpireKeyMap(weakValueMap2, value2);
|
||||
System.gc();
|
||||
assertThat(weakValueMap2.get(new MyBean("A"))).isEqualTo(new MyBean("B"));
|
||||
|
||||
ConcurrentMap<MyBean, MyBean> weakValueMap3 = MapUtil.createWeakValueConcurrentHashMap(10, 1);
|
||||
MyBean key3 = new MyBean("A");
|
||||
initExpireValueMap(weakValueMap3, key3);
|
||||
System.gc();
|
||||
assertThat(weakValueMap3.get(new MyBean("A"))).isNull();
|
||||
}
|
||||
|
||||
// 抽出子函数,使得Key/Value的生命周琦过期
|
||||
private void initExpireAllMap(ConcurrentMap<MyBean, MyBean> weakKeyMap) {
|
||||
MyBean key = new MyBean("A");
|
||||
MyBean value = new MyBean("B");
|
||||
weakKeyMap.put(key, value);
|
||||
assertThat(weakKeyMap.get(key)).isEqualTo(value);
|
||||
}
|
||||
|
||||
// 抽出子函数,使得key过期,value不过期
|
||||
private void initExpireKeyMap(ConcurrentMap<MyBean, MyBean> weakKeyMap, MyBean value) {
|
||||
MyBean key = new MyBean("A");
|
||||
weakKeyMap.put(key, value);
|
||||
assertThat(weakKeyMap.get(key)).isEqualTo(value);
|
||||
}
|
||||
|
||||
// 抽出子函数,使得key不过期,value过期
|
||||
private void initExpireValueMap(ConcurrentMap<MyBean, MyBean> weakKeyMap, MyBean key) {
|
||||
MyBean value = new MyBean("B");
|
||||
weakKeyMap.put(key, value);
|
||||
assertThat(weakKeyMap.get(key)).isEqualTo(value);
|
||||
}
|
||||
|
||||
// 抽出子函数,使得Key/Value的生命周琦过期
|
||||
private void initWeakValue(ConcurrentMap<MyBean, MyBean> weakKeyMap) {
|
||||
MyBean key = new MyBean("A");
|
||||
MyBean value = new MyBean("B");
|
||||
weakKeyMap.put(key, value);
|
||||
assertThat(weakKeyMap.get(new MyBean("A"))).isEqualTo(value);
|
||||
}
|
||||
|
||||
public static class MyBean {
|
||||
String name;
|
||||
|
||||
public MyBean(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
MyBean other = (MyBean) obj;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public enum EnumA {
|
||||
A, B, C
|
||||
}
|
||||
|
||||
@Test
|
||||
public void IntObjectHashMap(){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,18 +9,7 @@ import com.google.common.io.Files;
|
||||
|
||||
public class FilePathUtilTest {
|
||||
|
||||
private String sep = Platforms.FILE_PATH_SEPARATOR;
|
||||
|
||||
@Test
|
||||
public void getName() {
|
||||
assertThat(FilePathUtil.getFileName(sep + "a" + sep + "d" + sep + "b" + sep + "abc.txt")).isEqualTo("abc.txt");
|
||||
assertThat(FilePathUtil.getFileName("abc.txt")).isEqualTo("abc.txt");
|
||||
|
||||
assertThat(FilePathUtil.getFileExtension(sep + "a" + sep + "d" + sep + "b" + sep + "abc.txt")).isEqualTo("txt");
|
||||
assertThat(FilePathUtil.getFileExtension(sep + "a" + sep + "d" + sep + "b" + sep + "abc")).isEqualTo("");
|
||||
assertThat(FilePathUtil.getFileExtension(sep + "a" + sep + "d" + sep + "b" + sep + "abc.")).isEqualTo("");
|
||||
|
||||
}
|
||||
char sep = Platforms.FILE_PATH_SEPARATOR_CHAR;
|
||||
|
||||
@Test
|
||||
public void pathName() {
|
||||
@@ -40,5 +29,4 @@ public class FilePathUtilTest {
|
||||
System.out.println("the jar file contains Files.class" + FilePathUtil.getJarPath(Files.class));
|
||||
assertThat(FilePathUtil.getJarPath(Files.class)).endsWith("guava-20.0.jar");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package org.springside.modules.utils.io;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springside.modules.utils.number.RandomUtil;
|
||||
|
||||
public class FileTreeWalkerTest {
|
||||
|
||||
@Test
|
||||
public void listFile() throws IOException {
|
||||
File tmpDir = FileUtil.createTempDir();
|
||||
|
||||
List<File> all = FileTreeWalker.listAll(tmpDir);
|
||||
assertThat(all).hasSize(1);
|
||||
|
||||
List<File> files = FileTreeWalker.listFile(tmpDir);
|
||||
assertThat(files).hasSize(0);
|
||||
|
||||
FileUtil.touch(FilePathUtil.contact(tmpDir.getAbsolutePath(), "tmp-" + RandomUtil.nextInt()) + ".tmp");
|
||||
FileUtil.touch(FilePathUtil.contact(tmpDir.getAbsolutePath(), "tmp-" + RandomUtil.nextInt()) + ".abc");
|
||||
|
||||
String childDir = FilePathUtil.contact(tmpDir.getAbsolutePath(), "tmp-" + RandomUtil.nextInt());
|
||||
FileUtil.makeSureDirExists(childDir);
|
||||
|
||||
FileUtil.touch(FilePathUtil.contact(childDir, "tmp-" + RandomUtil.nextInt()) + ".tmp");
|
||||
|
||||
all = FileTreeWalker.listAll(tmpDir);
|
||||
assertThat(all).hasSize(5);
|
||||
|
||||
files = FileTreeWalker.listFile(tmpDir);
|
||||
assertThat(files).hasSize(3);
|
||||
|
||||
files = FileTreeWalker.listFileWithExtension(tmpDir, "tmp");
|
||||
assertThat(files).hasSize(2);
|
||||
|
||||
files = FileTreeWalker.listFileWithExtension(tmpDir, "tp");
|
||||
assertThat(files).hasSize(0);
|
||||
|
||||
files = FileTreeWalker.listFileWithWildcardFileName(tmpDir, "*.tmp");
|
||||
assertThat(files).hasSize(2);
|
||||
files = FileTreeWalker.listFileWithWildcardFileName(tmpDir, "*.tp");
|
||||
assertThat(files).hasSize(0);
|
||||
|
||||
files = FileTreeWalker.listFileWithRegexFileName(tmpDir, ".*\\.tmp");
|
||||
assertThat(files).hasSize(2);
|
||||
files = FileTreeWalker.listFileWithRegexFileName(tmpDir, ".*\\.tp");
|
||||
assertThat(files).hasSize(0);
|
||||
|
||||
FileUtil.deleteDir(tmpDir);
|
||||
|
||||
assertThat(FileUtil.isDirExists(tmpDir)).isFalse();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -68,36 +68,17 @@ public class FileUtilTest {
|
||||
}
|
||||
}
|
||||
|
||||
private String sep = Platforms.FILE_PATH_SEPARATOR;
|
||||
|
||||
@Test
|
||||
public void listFile() throws IOException {
|
||||
File tmpDir = FileUtil.createTempDir();
|
||||
public void getName() {
|
||||
|
||||
List<File> all = FileUtil.listAll(tmpDir);
|
||||
assertThat(all).hasSize(1);
|
||||
assertThat(FileUtil.getFileName(FilePathUtil.normalizePath("/a/d/b/abc.txt"))).isEqualTo("abc.txt");
|
||||
assertThat(FileUtil.getFileName("abc.txt")).isEqualTo("abc.txt");
|
||||
|
||||
List<File> files = FileUtil.listFile(tmpDir);
|
||||
assertThat(files).hasSize(0);
|
||||
|
||||
FileUtil.touch(FilePathUtil.contact(tmpDir.getAbsolutePath(), "tmp-" + RandomUtil.nextInt()) + ".tmp");
|
||||
FileUtil.touch(FilePathUtil.contact(tmpDir.getAbsolutePath(), "tmp-" + RandomUtil.nextInt()) + ".abc");
|
||||
|
||||
String childDir = FilePathUtil.contact(tmpDir.getAbsolutePath(), "tmp-" + RandomUtil.nextInt());
|
||||
FileUtil.makeSureDirExists(childDir);
|
||||
|
||||
FileUtil.touch(FilePathUtil.contact(childDir, "tmp-" + RandomUtil.nextInt()) + ".tmp");
|
||||
|
||||
all = FileUtil.listAll(tmpDir);
|
||||
assertThat(all).hasSize(5);
|
||||
|
||||
files = FileUtil.listFile(tmpDir);
|
||||
assertThat(files).hasSize(3);
|
||||
|
||||
files = FileUtil.listFileWithExtension(tmpDir, "tmp");
|
||||
assertThat(files).hasSize(2);
|
||||
|
||||
FileUtil.deleteDir(tmpDir);
|
||||
|
||||
assertThat(FileUtil.isDirExists(tmpDir)).isFalse();
|
||||
assertThat(FileUtil.getFileExtension(FilePathUtil.normalizePath("a/d/b/abc.txt"))).isEqualTo("txt");
|
||||
assertThat(FileUtil.getFileExtension(FilePathUtil.normalizePath("/a/d/b/abc"))).isEqualTo("");
|
||||
assertThat(FileUtil.getFileExtension(FilePathUtil.normalizePath("/a/d/b/abc."))).isEqualTo("");
|
||||
|
||||
}
|
||||
|
||||
|
||||
+12
@@ -22,10 +22,22 @@ public class FastMethodInvokerTest {
|
||||
age = fastGetAge.invoke(student2);
|
||||
assertThat(age).isEqualTo(30);
|
||||
|
||||
FastMethodInvoker fastGetAge2 = FastMethodInvoker.createGetter(Student.class, "age");
|
||||
age = fastGetAge2.invoke(student1);
|
||||
assertThat(age).isEqualTo(20);
|
||||
|
||||
age = fastGetAge2.invoke(student2);
|
||||
assertThat(age).isEqualTo(30);
|
||||
|
||||
FastMethodInvoker fastSetAge = FastMethodInvoker.create(Student.class, "setAge", int.class);
|
||||
fastSetAge.invoke(student1, 1);
|
||||
|
||||
assertThat(student1.getAge()).isEqualTo(1);
|
||||
|
||||
FastMethodInvoker fastSetAge2 = FastMethodInvoker.createSetter(Student.class, "age", int.class);
|
||||
fastSetAge2.invoke(student1, 3);
|
||||
|
||||
assertThat(student1.getAge()).isEqualTo(3);
|
||||
}
|
||||
|
||||
public static class Student {
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package org.springside.modules.utils.text;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class WildcardMatcherTest {
|
||||
|
||||
@Test
|
||||
public void matchString() {
|
||||
assertThat(WildcardMatcher.match("abc", "*")).isTrue();
|
||||
assertThat(WildcardMatcher.match("abc", "*c")).isTrue();
|
||||
assertThat(WildcardMatcher.match("abc", "a*")).isTrue();
|
||||
assertThat(WildcardMatcher.match("abc", "a*c")).isTrue();
|
||||
|
||||
assertThat(WildcardMatcher.match("abc", "a?c")).isTrue();
|
||||
assertThat(WildcardMatcher.match("abcd", "a?c?")).isTrue();
|
||||
assertThat(WildcardMatcher.match("abcd", "a??d")).isTrue();
|
||||
|
||||
assertThat(WildcardMatcher.match("abcde", "a*d?")).isTrue();
|
||||
|
||||
assertThat(WildcardMatcher.match("abcde", "a*d")).isFalse();
|
||||
assertThat(WildcardMatcher.match("abcde", "a*x")).isFalse();
|
||||
assertThat(WildcardMatcher.match("abcde", "a*df")).isFalse();
|
||||
|
||||
assertThat(WildcardMatcher.match("abcde", "?abcd")).isFalse();
|
||||
|
||||
assertThat(WildcardMatcher.match("ab\\\\*cde", "ab\\\\*c*")).isTrue();
|
||||
assertThat(WildcardMatcher.match("ab\\\\*cde", "ab\\\\*?de")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchPath() {
|
||||
assertThat(WildcardMatcher.matchPath("/a/b/dd", "**")).isTrue();
|
||||
|
||||
assertThat(WildcardMatcher.matchPath("/a/b/dd", "**/dd")).isTrue();
|
||||
assertThat(WildcardMatcher.matchPath("/a/b/c/dd", "/a/**/dd")).isTrue();
|
||||
assertThat(WildcardMatcher.matchPath("/a/b/dd", "/a/*/dd")).isTrue();
|
||||
assertThat(WildcardMatcher.matchPath("/a/b/dd", "/a/*/d?")).isTrue();
|
||||
assertThat(WildcardMatcher.matchPath("/a/b/ddxxa", "/a/*/dd*")).isTrue();
|
||||
assertThat(WildcardMatcher.matchPath("/a/b/ddxxa", "/a/?/dd*")).isTrue();
|
||||
assertThat(WildcardMatcher.matchPath("a/b/ddxxa", "a/?/dd*")).isTrue();
|
||||
assertThat(WildcardMatcher.matchPath("a/b/dd", "**/dd")).isTrue();
|
||||
|
||||
|
||||
assertThat(WildcardMatcher.matchPath("/a/b/c/dd", "/a/*/dd")).isFalse();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user