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<path>() {
      @Override
      public boolean accept(Path entry) throws IOException {
        return matcher.matches(entry.getFileName()) &amp;&amp; !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

代码

JDKglob 相关的内容主要在 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<path> fileVisitor = new SimpleFileVisitor<path>() {
    @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();
}

Glob 语句转正则表达式的实现:

参考

Glob with Java NIO

Finding Files

What Is a Glob?

glob (programming)

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

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

private List<file> getMatchingFilesNoCache() {
    List<file> result = Lists.newArrayList();

    List<path> paths = recurseFolder(parentDir);
    for(Path path:paths){
      try (DirectoryStream<path> stream = Files.newDirectoryStream(path, fileFilter)) {
        for (Path entry : stream) {
          result.add(entry.toFile());
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    return result;
  }

  public List<path> recurseFolder(File root) {
    List<path> allParentFolders = new ArrayList&lt;&gt;();
    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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值