ANT 表达式(也称为 Ant-style Path Patterns 或 Ant 路径模式)是一种用于匹配文件路径或目录结构的简单模式匹配语法。它最初由 Apache Ant 构建工具引入,广泛应用于各种构建工具、配置文件、文件系统操作等场景中,用于指定文件或目录的匹配规则。
ANT 表达式的语法非常直观,允许使用通配符来匹配文件名、目录名或路径中的某些部分。它类似于 Unix Shell 的路径匹配规则,但有一些特定的扩展和差异。
ANT 表达式的常见符号
-
*
(星号):- 匹配任意数量的字符(不包括斜杠
/
),即它可以匹配文件名或目录名中的任意字符。 - 示例:
*.txt
:匹配所有以.txt
结尾的文件。file*
:匹配所有以file
开头的文件或目录。
- 匹配任意数量的字符(不包括斜杠
-
?
(问号):- 匹配单个字符(不包括斜杠
/
),即它只能匹配一个字符。 - 示例:
file?.txt
:匹配file1.txt
、file2.txt
等,但不会匹配file10.txt
,因为?
只匹配一个字符。
- 匹配单个字符(不包括斜杠
-
**
(双星号):- 匹配任意数量的字符,包括斜杠
/
,即它可以匹配多级目录。 - 示例:
**/*.txt
:匹配任意目录下的所有.txt
文件,无论嵌套多少层。src/**/Main.java
:匹配src
目录及其子目录下的所有Main.java
文件。
- 匹配任意数量的字符,包括斜杠
-
{}
(花括号):- 用于定义多个可选的路径或文件名,类似于正则表达式中的“或”操作。
- 示例:
src/{main,test}/**/*.java
:匹配src/main
和src/test
目录及其子目录下的所有.java
文件。file{1,2,3}.txt
:匹配file1.txt
、file2.txt
和file3.txt
。
-
!
(感叹号):- 用于排除某些路径或文件,通常与
**
或其他通配符结合使用。 - 示例:
**/*.java,!src/test/**/*.java
:匹配所有.java
文件,但排除src/test
目录及其子目录下的.java
文件。
- 用于排除某些路径或文件,通常与
ANT 表达式的应用场景
ANT 表达式广泛应用于以下场景:
-
构建工具:
- Apache Ant、Maven、Gradle 等构建工具使用 ANT 表达式来指定需要编译、打包或复制的文件和目录。
- 例如,在 Maven 中,
<resources>
配置可以使用 ANT 表达式来指定哪些文件应该包含在最终的 JAR 或 WAR 文件中。
-
文件系统操作:
- 在文件系统操作中,ANT 表达式用于匹配文件和目录,执行批量操作(如复制、删除、移动等)。
- 例如,Spring Boot 的
application.properties
文件中可以使用 ANT 表达式来指定静态资源的路径。
-
日志配置:
- 在日志框架(如 Logback、Log4j)中,ANT 表达式用于指定日志文件的滚动策略或归档路径。
- 例如,Logback 的
RollingFileAppender
可以使用 ANT 表达式来定义日志文件的命名模式。
-
Web 框架:
- 在 Spring MVC、Spring Boot 等 Web 框架中,ANT 表达式用于定义 URL 路径匹配规则。
- 例如,
@RequestMapping("/api/v1/*")
可以匹配/api/v1
下的所有路径。
示例
假设有一个如下所示的目录结构:
project/
├── src
│ ├── main
│ │ └── java
│ │ └── com
│ │ └── example
│ │ ├── App.java
│ │ └── Service.java
│ └── test
│ └── java
│ └── com
│ └── example
│ └── AppTest.java
└── build
└── classes
└── com
└── example
├── App.class
└── Service.class
使用 ANT 表达式进行匹配:
-
匹配所有
.java
文件:**/*.java
:匹配src/main/java/com/example/App.java
、src/main/java/com/example/Service.java
和src/test/java/com/example/AppTest.java
。
-
匹配
src
目录下的所有.java
文件:src/**/*.java
:匹配src/main/java/com/example/App.java
和src/main/java/com/example/Service.java
,但不匹配src/test/java/com/example/AppTest.java
。
-
匹配
src/main
目录下的所有.java
文件:src/main/**/*.java
:仅匹配src/main/java/com/example/App.java
和src/main/java/com/example/Service.java
。
-
排除测试文件:
**/*.java,!src/test/**/*.java
:匹配所有.java
文件,但排除src/test/java/com/example/AppTest.java
。
-
匹配特定包下的文件:
src/main/java/com/example/*.java
:仅匹配src/main/java/com/example
目录下的.java
文件,即App.java
和Service.java
。
-
匹配多个目录下的文件:
src/{main,test}/**/*.java
:匹配src/main
和src/test
目录下的所有.java
文件。
常见的ANT工具
1. Spring Framework 的 PathMatcher
Spring 框架提供了一个强大的 PathMatcher
接口,以及它的默认实现 AntPathMatcher
,专门用于处理 ANT 风格的路径模式。AntPathMatcher
支持所有常见的 ANT 表达式符号(如 *
、**
、?
等),并且可以用于匹配文件路径、URL 路径等。
import org.springframework.util.AntPathMatcher;
public class AntPathMatcherExample {
public static void main(String[] args) {
AntPathMatcher pathMatcher = new AntPathMatcher();
// 匹配单个文件
System.out.println(pathMatcher.match("*.txt", "file.txt")); // true
System.out.println(pathMatcher.match("*.txt", "file.java")); // false
// 匹配多级目录
System.out.println(pathMatcher.match("src/**/Main.java", "src/main/java/com/example/Main.java")); // true
System.out.println(pathMatcher.match("src/**/Main.java", "src/test/java/com/example/MainTest.java")); // false
// 匹配多个路径
System.out.println(pathMatcher.match("src/{main,test}/**/*.java", "src/main/java/com/example/App.java")); // true
System.out.println(pathMatcher.match("src/{main,test}/**/*.java", "src/test/java/com/example/AppTest.java")); // true
}
}
主要方法:
boolean match(String pattern, String path)
:判断给定的路径是否匹配指定的模式。String extractPathWithinPattern(String pattern, String path)
:从路径中提取出匹配模式的部分。String[] extractUriTemplateVariables(String pattern, String path)
:从路径中提取出 URI 模板变量(如果模式中包含{}
)。
优点:
- 灵活性:支持复杂的路径模式,包括
*
、**
、?
和{}
。 - 广泛使用:
AntPathMatcher
在 Spring MVC 中用于 URL 路径匹配,因此它经过了大量实际应用的验证。
引入依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.20</version> <!-- 请根据需要选择合适的版本 -->
</dependency>
2. Apache Commons IO 的 WildcardFileFilter
Apache Commons IO 提供了一个 WildcardFileFilter
类,它可以用于根据 ANT 风格的通配符模式过滤文件。虽然它不支持 **
这样的多级目录匹配,但它可以处理 *
和 ?
等简单的通配符。
import org.apache.commons.io.filefilter.WildcardFileFilter;
import java.io.File;
import java.io.FilenameFilter;
public class WildcardFileFilterExample {
public static void main(String[] args) {
File dir = new File("path/to/directory");
// 创建一个通配符过滤器
FilenameFilter filter = new WildcardFileFilter("*.txt");
// 列出所有匹配的文件
File[] files = dir.listFiles(filter);
if (files != null) {
for (File file : files) {
System.out.println(file.getName());
}
}
}
}
优点:
- 简单易用:适用于简单的文件过滤场景,特别是当你只需要使用
*
和?
通配符时。 - 轻量级:
Apache Commons IO
是一个非常流行的库,提供了许多与文件操作相关的工具类。
引入依赖:
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version> <!-- 请根据需要选择合适的版本 -->
</dependency>
3. Apache Ant 自身的 PatternSet
和 DirectoryScanner
Apache Ant 提供了 PatternSet
和 DirectoryScanner
类,它们可以用于处理复杂的路径模式匹配。DirectoryScanner
可以扫描目录并根据指定的模式筛选文件,支持 *
、**
、?
等通配符。
import org.apache.tools.ant.types.PatternSet;
import org.apache.tools.ant.DirectoryScanner;
import java.io.File;
public class DirectoryScannerExample {
public static void main(String[] args) {
File basedir = new File("path/to/directory");
// 创建 PatternSet 并添加包含和排除模式
PatternSet patternSet = new PatternSet();
patternSet.setIncludes(new String[]{"**/*.java"});
patternSet.setExcludes(new String[]{"**/test/**/*.java"});
// 创建 DirectoryScanner 并设置模式
DirectoryScanner scanner = new DirectoryScanner();
scanner.setBasedir(basedir);
scanner.setIncludes(patternSet.getIncludePatterns(null));
scanner.setExcludes(patternSet.getExcludePatterns(null));
scanner.scan();
// 获取匹配的文件列表
String[] files = scanner.getIncludedFiles();
for (String file : files) {
System.out.println(file);
}
}
}
优点:
- 功能强大:
DirectoryScanner
支持复杂的路径模式匹配,包括**
多级目录匹配和排除模式。 - 与 Ant 兼容:如果你已经在项目中使用了 Ant 构建工具,可以直接复用这些类。
引入依赖:
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
<version>1.10.12</version> <!-- 请根据需要选择合适的版本 -->
</dependency>
4. Google Guava 的 PatternMatcher
Hutool 的 AntPathMatcher
虽然 Google Guava 库本身并没有直接提供对 ANT 风格路径模式的支持,但它的 PatternMatcher
类可以用于简单的正则表达式匹配。如果你需要更复杂的路径匹配逻辑,建议使用上述提到的其他库。
5. Hutool 的 AntPathMatcher
Hutool 的 AntPathMatcher
类提供了与 Spring 的 AntPathMatcher
类似的功能,支持常见的 ANT 风格路径模式(如 *
、**
、?
等)。你可以使用它来匹配文件路径、URL 路径等。
import cn.hutool.core.io.AntPathMatcher;
public class AntPathMatcherExample {
public static void main(String[] args) {
// 创建 AntPathMatcher 实例
AntPathMatcher matcher = new AntPathMatcher();
// 匹配单个文件
System.out.println(matcher.match("*.txt", "file.txt")); // true
System.out.println(matcher.match("*.txt", "file.java")); // false
// 匹配多级目录
System.out.println(matcher.match("src/**/Main.java", "src/main/java/com/example/Main.java")); // true
System.out.println(matcher.match("src/**/Main.java", "src/test/java/com/example/MainTest.java")); // false
// 匹配多个路径
System.out.println(matcher.match("src/{main,test}/**/*.java", "src/main/java/com/example/App.java")); // true
System.out.println(matcher.match("src/{main,test}/**/*.java", "src/test/java/com/example/AppTest.java")); // true
// 排除某些路径
System.out.println(matcher.match("src/**/Main.java,!src/test/**/*.java", "src/main/java/com/example/Main.java")); // true
System.out.println(matcher.match("src/**/Main.java,!src/test/**/*.java", "src/test/java/com/example/MainTest.java")); // false
// 提取路径中的变量
String pattern = "users/{userId}/orders/{orderId}";
String path = "users/123/orders/456";
System.out.println(matcher.extractUriTemplateVariables(pattern, path)); // {userId=123, orderId=456}
}
}
引入依赖:
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.11</version> <!-- 请根据需要选择合适的版本 -->
</dependency>