001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.io.filefilter; 018 019import java.io.File; 020import java.io.Serializable; 021import java.nio.file.FileVisitResult; 022import java.nio.file.Path; 023import java.nio.file.attribute.BasicFileAttributes; 024import java.util.Objects; 025import java.util.function.Function; 026import java.util.regex.Pattern; 027 028import org.apache.commons.io.IOCase; 029import org.apache.commons.io.file.PathUtils; 030 031/** 032 * Filters files using supplied regular expression(s). 033 * <p> 034 * See java.util.regex.Pattern for regex matching rules. 035 * </p> 036 * <h2>Using Classic IO</h2> 037 * <p> 038 * e.g. 039 * 040 * <pre> 041 * File dir = FileUtils.current(); 042 * FileFilter fileFilter = new RegexFileFilter("^.*[tT]est(-\\d+)?\\.java$"); 043 * File[] files = dir.listFiles(fileFilter); 044 * for (String file : files) { 045 * System.out.println(file); 046 * } 047 * </pre> 048 * 049 * <h2>Using NIO</h2> 050 * 051 * <pre> 052 * final Path dir = PathUtils.current(); 053 * final AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(new RegexFileFilter("^.*[tT]est(-\\d+)?\\.java$")); 054 * // 055 * // Walk one directory 056 * Files.<strong>walkFileTree</strong>(dir, Collections.emptySet(), 1, visitor); 057 * System.out.println(visitor.getPathCounters()); 058 * System.out.println(visitor.getFileList()); 059 * // 060 * visitor.getPathCounters().reset(); 061 * // 062 * // Walk directory tree 063 * Files.<strong>walkFileTree</strong>(dir, visitor); 064 * System.out.println(visitor.getPathCounters()); 065 * System.out.println(visitor.getDirList()); 066 * System.out.println(visitor.getFileList()); 067 * </pre> 068 * <h2>Deprecating Serialization</h2> 069 * <p> 070 * <em>Serialization is deprecated and will be removed in 3.0.</em> 071 * </p> 072 * 073 * @since 1.4 074 */ 075public class RegexFileFilter extends AbstractFileFilter implements Serializable { 076 077 private static final long serialVersionUID = 4269646126155225062L; 078 079 /** 080 * Compiles the given pattern source. 081 * 082 * @param pattern the source pattern. 083 * @param flags the compilation flags. 084 * @return a new Pattern. 085 */ 086 private static Pattern compile(final String pattern, final int flags) { 087 Objects.requireNonNull(pattern, "pattern"); 088 return Pattern.compile(pattern, flags); 089 } 090 091 /** 092 * Converts IOCase to Pattern compilation flags. 093 * 094 * @param ioCase case-sensitivity. 095 * @return Pattern compilation flags. 096 */ 097 private static int toFlags(final IOCase ioCase) { 098 return IOCase.isCaseSensitive(ioCase) ? 0 : Pattern.CASE_INSENSITIVE; 099 } 100 101 /** The regular expression pattern that will be used to match file names. */ 102 private final Pattern pattern; 103 104 /** How convert a path to a string. */ 105 private final transient Function<Path, String> pathToString; 106 107 /** 108 * Constructs a new regular expression filter for a compiled regular expression 109 * 110 * @param pattern regular expression to match. 111 * @throws NullPointerException if the pattern is null. 112 */ 113 @SuppressWarnings("unchecked") 114 public RegexFileFilter(final Pattern pattern) { 115 this(pattern, (Function<Path, String> & Serializable) PathUtils::getFileNameString); 116 } 117 118 /** 119 * Constructs a new regular expression filter for a compiled regular expression 120 * 121 * @param pattern regular expression to match. 122 * @param pathToString How convert a path to a string. 123 * @throws NullPointerException if the pattern is null. 124 * @since 2.10.0 125 */ 126 public RegexFileFilter(final Pattern pattern, final Function<Path, String> pathToString) { 127 Objects.requireNonNull(pattern, "pattern"); 128 this.pattern = pattern; 129 this.pathToString = pathToString != null ? pathToString : Objects::toString; 130 } 131 132 /** 133 * Constructs a new regular expression filter. 134 * 135 * @param pattern regular string expression to match 136 * @throws NullPointerException if the pattern is null 137 */ 138 public RegexFileFilter(final String pattern) { 139 this(pattern, 0); 140 } 141 142 /** 143 * Constructs a new regular expression filter with the specified flags. 144 * 145 * @param pattern regular string expression to match 146 * @param flags pattern flags - e.g. {@link Pattern#CASE_INSENSITIVE} 147 * @throws IllegalArgumentException if the pattern is null 148 */ 149 public RegexFileFilter(final String pattern, final int flags) { 150 this(compile(pattern, flags)); 151 } 152 153 /** 154 * Constructs a new regular expression filter with the specified flags case sensitivity. 155 * 156 * @param pattern regular string expression to match 157 * @param ioCase how to handle case sensitivity, null means case-sensitive 158 * @throws IllegalArgumentException if the pattern is null 159 */ 160 public RegexFileFilter(final String pattern, final IOCase ioCase) { 161 this(compile(pattern, toFlags(ioCase))); 162 } 163 164 /** 165 * Checks to see if the file name matches one of the regular expressions. 166 * 167 * @param dir the file directory (ignored) 168 * @param name the file name 169 * @return true if the file name matches one of the regular expressions 170 */ 171 @Override 172 public boolean accept(final File dir, final String name) { 173 return pattern.matcher(name).matches(); 174 } 175 176 /** 177 * Checks to see if the file name matches one of the regular expressions. 178 * 179 * @param path the path 180 * @param attributes the path's basic attributes (may be null). 181 * @return true if the file name matches one of the regular expressions 182 */ 183 @Override 184 public FileVisitResult accept(final Path path, final BasicFileAttributes attributes) { 185 final String result = pathToString.apply(path); 186 return toFileVisitResult(result != null && pattern.matcher(result).matches()); 187 } 188 189 /** 190 * Returns a debug string. 191 * 192 * @since 2.10.0 193 */ 194 @Override 195 public String toString() { 196 return "RegexFileFilter [pattern=" + pattern + "]"; 197 } 198 199}