java glob paths_flume-taildir/glob语法/路径迭代

flume-taildir/glob语法/路径迭代

最近在使用flume的taildir做多文件监控,发现配置路径的增则表达式不起作用,跟踪源码发现:

TaildirMatcher(String fileGroup, String filePattern, boolean cachePatternMatching) {

// store whatever came from configuration

this.fileGroup = fileGroup;

this.filePattern = filePattern;

this.cachePatternMatching = cachePatternMatching;

// calculate final members

File f = new File(filePattern);

this.parentDir = f.getParentFile();

String regex = f.getName();

final PathMatcher matcher = FS.getPathMatcher("regex:" + regex);

this.fileFilter = new DirectoryStream.Filter() {

@Override

public boolean accept(Path entry) throws IOException {

return matcher.matches(entry.getFileName()) && !Files.isDirectory(entry);

}

};

// sanity check

Preconditions.checkState(parentDir.exists(),

"Directory does not exist: " + parentDir.getAbsolutePath());

}

其中的

final PathMatcher matcher = FS.getPathMatcher("regex:" + regex);

这一行是用来做正则匹配的。

这里的参数有两种类型:一是glob;另一是regex的。flume默认使用的是regex类型,其是java.util.regex.Pattern的java类型的正则表达式。这两种类型的正则匹配不一样,所以导致配置路径不起作用。至于glob则是下面介绍的一种

Glob

Glob 是一种模式匹配,类似于正则表达式但是语法相对简单。Glob 语句是一个含有 *,?{}[] 这些特殊字符的字符串,并与目标字符串匹配。可以用来做文件路径匹配或文件查找。例如 Linux 下的命令 ls *.txt ,其中的 *.txt 就是一个 glob 语句。

语法规则

Java 语言中的 Glob 语法遵循几个简单的规则:

*

匹配任意个数的字符,包括空。不包括路径边界 / 或 \。例如 /path/*/abc 可以匹配 /path/a/abc 和 /path/b/abc等。

**

和一个星号类似,区别是可以跨路径边界,一般用来匹配多级目录。例如 /path/**/abc 可以用来匹配 /path/a/abc、/path/b/abc 、/path/a/b/abc、/path/a/b/c/abc 等。

一个问号 ?

匹配任意一个字符

{}

大括号用来指定一个子模式匹配集合,例如:{sun,moon,stars} 可以匹配 sun moon starts , {temp*, tmp*} 可以匹配任何以 temp tmp 开头的字符串等。

[]

方括号表示匹配括号内的任意一个单个字符,当有 - 时表示匹配任意一个连续范围内的单个字符。例如:[aeiou] 匹配任意一个小写元音字符,[0-9] 匹配任意一个数字,[A-Z] 匹配任意一个大写字母,[a-z,A-Z] 匹配任意一个大写或小写字母。另外,在方括号内, * ? \ 字符仅匹配它们自身。

任意其它字符

任意的其他字符表示匹配它们自身。

反斜杠\转义

匹配 * ? 或其他特殊字符需要使用反斜杠\转义。例如: \\ 匹配一个反斜杠,\? 匹配一个问号。

举例说明

Glob

说明

*.log

匹配所有.log结尾的字符串

??

匹配所有有两个数字或字母构成的字符串,aa,a1

*[0-9]*

匹配所有含有一个数字的字符串

*.{htm,html,pdf}

匹配所有以 .htm .html 或 .pdf 结尾的字符串

a?*.java

匹配所有以 a 开头,且a 之后至少由一个字母或数字,且以 .java 结尾的字符传

{foo*,[0-9]}

匹配所有以 foo 开头,或含有数字的字符串,如 foobar x1y foo1xyz

代码

JDK 中 glob 相关的内容主要在 java.nio.file 包内,其中 glob 语法转正则表达式的实现在 sun.nio.fs.Globs.java 中。下面代码是一个寻找/lihao/test/ 目录下所有 jpg 文件的例子:

String match = "glob:/lihao/test/**/*.jpg";

final PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher(match);

SimpleFileVisitor fileVisitor = new SimpleFileVisitor() {

@Override

public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)

throws IOException {

if (pathMatcher.matches(file)) {

System.out.println("find: " + file.toFile().toString())

}

return super.visitFile(file, attrs);

}

};

try {

Files.walkFileTree(Paths.get(dir.getPath()), fileVisitor);

} catch (IOException e) {

e.printStackTrace();

}

参考

taildir监控文件迭代问题源码修改

在TaildirMatcher类中使用如下代码覆盖相应的代码即可将完成路径的迭代问题

private List getMatchingFilesNoCache() {

List result = Lists.newArrayList();

List paths = recurseFolder(parentDir);

for(Path path:paths){

try (DirectoryStream stream = Files.newDirectoryStream(path, fileFilter)) {

for (Path entry : stream) {

result.add(entry.toFile());

}

} catch (IOException e) {

e.printStackTrace();

}

}

return result;

}

public List recurseFolder(File root) {

List allParentFolders = new ArrayList<>();

if (root.exists()) {

allParentFolders.add(root.toPath());

File[] files = root.listFiles();

if (null == files || files.length == 0) {

return allParentFolders;

} else {

for (File subFile : files) {

if (subFile.isDirectory()) {

allParentFolders.addAll(recurseFolder(subFile));

}

}

}

}

return allParentFolders;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值