flume-taildirglob语法路径迭代

    xiaoxiao2021-04-15  358

    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

    代码

    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<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<>(); 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)