1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.commons.io.filefilter; 18 19 import java.io.File; 20 import java.io.Serializable; 21 import java.nio.file.FileVisitResult; 22 import java.nio.file.Path; 23 import java.nio.file.attribute.BasicFileAttributes; 24 import java.time.Instant; 25 import java.util.Date; 26 27 import org.apache.commons.io.FileUtils; 28 import org.apache.commons.io.file.PathUtils; 29 30 /** 31 * Filters files based on a cutoff time, can filter either newer files or files equal to or older. 32 * <p> 33 * For example, to print all files and directories in the current directory older than one day: 34 * </p> 35 * <h2>Using Classic IO</h2> 36 * <pre> 37 * Path dir = PathUtils.current(); 38 * // We are interested in files older than one day 39 * Instant cutoff = Instant.now().minus(Duration.ofDays(1)); 40 * String[] files = dir.list(new AgeFileFilter(cutoff)); 41 * for (String file : files) { 42 * System.out.println(file); 43 * } 44 * </pre> 45 * 46 * <h2>Using NIO</h2> 47 * <pre> 48 * Path dir = PathUtils.current(); 49 * // We are interested in files older than one day 50 * Instant cutoff = Instant.now().minus(Duration.ofDays(1)); 51 * AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(new AgeFileFilter(cutoff)); 52 * // 53 * // Walk one dir 54 * Files.<b>walkFileTree</b>(dir, Collections.emptySet(), 1, visitor); 55 * System.out.println(visitor.getPathCounters()); 56 * System.out.println(visitor.getFileList()); 57 * // 58 * visitor.getPathCounters().reset(); 59 * // 60 * // Walk dir tree 61 * Files.<b>walkFileTree</b>(dir, visitor); 62 * System.out.println(visitor.getPathCounters()); 63 * System.out.println(visitor.getDirList()); 64 * System.out.println(visitor.getFileList()); 65 * </pre> 66 * 67 * @see FileFilterUtils#ageFileFilter(Date) 68 * @see FileFilterUtils#ageFileFilter(File) 69 * @see FileFilterUtils#ageFileFilter(long) 70 * @see FileFilterUtils#ageFileFilter(Date, boolean) 71 * @see FileFilterUtils#ageFileFilter(File, boolean) 72 * @see FileFilterUtils#ageFileFilter(long, boolean) 73 * @since 1.2 74 */ 75 public class AgeFileFilter extends AbstractFileFilter implements Serializable { 76 77 private static final long serialVersionUID = -2132740084016138541L; 78 79 /** Whether the files accepted will be older or newer. */ 80 private final boolean acceptOlder; 81 82 /** The cutoff time threshold measured in milliseconds since the epoch (00:00:00 GMT, January 1, 1970). */ 83 private final Instant cutoffInstant; 84 85 /** 86 * Constructs a new age file filter for files older than (at or before) a certain cutoff date. 87 * 88 * @param cutoffDate the threshold age of the files 89 */ AgeFileFilter(final Date cutoffDate)90 public AgeFileFilter(final Date cutoffDate) { 91 this(cutoffDate, true); 92 } 93 94 /** 95 * Constructs a new age file filter for files on any one side of a certain cutoff date. 96 * 97 * @param cutoffDate the threshold age of the files 98 * @param acceptOlder if true, older files (at or before the cutoff) are accepted, else newer ones (after the 99 * cutoff). 100 */ AgeFileFilter(final Date cutoffDate, final boolean acceptOlder)101 public AgeFileFilter(final Date cutoffDate, final boolean acceptOlder) { 102 this(cutoffDate.toInstant(), acceptOlder); 103 } 104 105 /** 106 * Constructs a new age file filter for files older than (at or before) a certain File (whose last modification time 107 * will be used as reference). 108 * 109 * @param cutoffReference the file whose last modification time is used as the threshold age of the files 110 */ AgeFileFilter(final File cutoffReference)111 public AgeFileFilter(final File cutoffReference) { 112 this(cutoffReference, true); 113 } 114 115 /** 116 * Constructs a new age file filter for files on any one side of a certain File (whose last modification time will 117 * be used as reference). 118 * 119 * @param cutoffReference the file whose last modification time is used as the threshold age of the files 120 * @param acceptOlder if true, older files (at or before the cutoff) are accepted, else newer ones (after the 121 * cutoff). 122 */ AgeFileFilter(final File cutoffReference, final boolean acceptOlder)123 public AgeFileFilter(final File cutoffReference, final boolean acceptOlder) { 124 this(FileUtils.lastModifiedUnchecked(cutoffReference), acceptOlder); 125 } 126 127 /** 128 * Constructs a new age file filter for files equal to or older than a certain cutoff. 129 * 130 * @param cutoffInstant The cutoff time threshold since the epoch (00:00:00 GMT, January 1, 1970). 131 * @since 2.12.0 132 */ AgeFileFilter(final Instant cutoffInstant)133 public AgeFileFilter(final Instant cutoffInstant) { 134 this(cutoffInstant, true); 135 } 136 137 /** 138 * Constructs a new age file filter for files on any one side of a certain cutoff. 139 * 140 * @param cutoffInstant The cutoff time threshold since the epoch (00:00:00 GMT, January 1, 1970). 141 * @param acceptOlder if true, older files (at or before the cutoff) are accepted, else newer ones (after the cutoff). 142 * @since 2.12.0 143 */ AgeFileFilter(final Instant cutoffInstant, final boolean acceptOlder)144 public AgeFileFilter(final Instant cutoffInstant, final boolean acceptOlder) { 145 this.acceptOlder = acceptOlder; 146 this.cutoffInstant = cutoffInstant; 147 } 148 149 /** 150 * Constructs a new age file filter for files equal to or older than a certain cutoff 151 * 152 * @param cutoffMillis The cutoff time threshold measured in milliseconds since the epoch (00:00:00 GMT, January 1, 153 * 1970). 154 */ AgeFileFilter(final long cutoffMillis)155 public AgeFileFilter(final long cutoffMillis) { 156 this(Instant.ofEpochMilli(cutoffMillis), true); 157 } 158 159 /** 160 * Constructs a new age file filter for files on any one side of a certain cutoff. 161 * 162 * @param cutoffMillis The cutoff time threshold measured in milliseconds since the epoch (00:00:00 GMT, January 1, 163 * 1970). 164 * @param acceptOlder if true, older files (at or before the cutoff) are accepted, else newer ones (after the 165 * cutoff). 166 */ AgeFileFilter(final long cutoffMillis, final boolean acceptOlder)167 public AgeFileFilter(final long cutoffMillis, final boolean acceptOlder) { 168 this(Instant.ofEpochMilli(cutoffMillis), acceptOlder); 169 } 170 171 /** 172 * Checks to see if the last modification of the file matches cutoff favorably. 173 * <p> 174 * If last modification time equals cutoff and newer files are required, file <b>IS NOT</b> selected. If last 175 * modification time equals cutoff and older files are required, file <b>IS</b> selected. 176 * </p> 177 * 178 * @param file the File to check 179 * @return true if the file name matches 180 */ 181 @Override accept(final File file)182 public boolean accept(final File file) { 183 return acceptOlder != FileUtils.isFileNewer(file, cutoffInstant); 184 } 185 186 /** 187 * Checks to see if the last modification of the file matches cutoff favorably. 188 * <p> 189 * If last modification time equals cutoff and newer files are required, file <b>IS NOT</b> selected. If last 190 * modification time equals cutoff and older files are required, file <b>IS</b> selected. 191 * </p> 192 * @param file the File to check 193 * 194 * @return true if the file name matches 195 * @since 2.9.0 196 */ 197 @Override accept(final Path file, final BasicFileAttributes attributes)198 public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) { 199 return get(() -> toFileVisitResult(acceptOlder != PathUtils.isNewer(file, cutoffInstant))); 200 } 201 202 /** 203 * Provide a String representation of this file filter. 204 * 205 * @return a String representation 206 */ 207 @Override toString()208 public String toString() { 209 final String condition = acceptOlder ? "<=" : ">"; 210 return super.toString() + "(" + condition + cutoffInstant + ")"; 211 } 212 } 213