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 * https://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 directoryectory
54 * Files.<strong>walkFileTree</strong>(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 directory tree
61 * Files.<strong>walkFileTree</strong>(dir, visitor);
62 * System.out.println(visitor.getPathCounters());
63 * System.out.println(visitor.getDirList());
64 * System.out.println(visitor.getFileList());
65 * </pre>
66 * <h2>Deprecating Serialization</h2>
67 * <p>
68 * <em>Serialization is deprecated and will be removed in 3.0.</em>
69 * </p>
70 *
71 * @see FileFilterUtils#ageFileFilter(Date)
72 * @see FileFilterUtils#ageFileFilter(File)
73 * @see FileFilterUtils#ageFileFilter(long)
74 * @see FileFilterUtils#ageFileFilter(Date, boolean)
75 * @see FileFilterUtils#ageFileFilter(File, boolean)
76 * @see FileFilterUtils#ageFileFilter(long, boolean)
77 * @since 1.2
78 */
79 public class AgeFileFilter extends AbstractFileFilter implements Serializable {
80
81 private static final long serialVersionUID = -2132740084016138541L;
82
83 /** Whether the files accepted will be older or newer. */
84 private final boolean acceptOlder;
85
86 /** The cutoff time threshold measured in milliseconds since the epoch (00:00:00 GMT, January 1, 1970). */
87 private final Instant cutoffInstant;
88
89 /**
90 * Constructs a new age file filter for files older than (at or before) a certain cutoff date.
91 *
92 * @param cutoffDate the threshold age of the files.
93 */
94 public AgeFileFilter(final Date cutoffDate) {
95 this(cutoffDate, true);
96 }
97
98 /**
99 * Constructs a new age file filter for files on any one side of a certain cutoff date.
100 *
101 * @param cutoffDate the threshold age of the files.
102 * @param acceptOlder if true, older files (at or before the cutoff) are accepted, else newer ones (after the
103 * cutoff).
104 */
105 public AgeFileFilter(final Date cutoffDate, final boolean acceptOlder) {
106 this(cutoffDate.toInstant(), acceptOlder);
107 }
108
109 /**
110 * Constructs a new age file filter for files older than (at or before) a certain File (whose last modification time
111 * will be used as reference).
112 *
113 * @param cutoffReference the file whose last modification time is used as the threshold age of the files.
114 */
115 public AgeFileFilter(final File cutoffReference) {
116 this(cutoffReference, true);
117 }
118
119 /**
120 * Constructs a new age file filter for files on any one side of a certain File (whose last modification time will
121 * be used as reference).
122 *
123 * @param cutoffReference the file whose last modification time is used as the threshold age of the files.
124 * @param acceptOlder if true, older files (at or before the cutoff) are accepted, else newer ones (after the
125 * cutoff).
126 */
127 public AgeFileFilter(final File cutoffReference, final boolean acceptOlder) {
128 this(FileUtils.lastModifiedUnchecked(cutoffReference), acceptOlder);
129 }
130
131 /**
132 * Constructs a new age file filter for files equal to or older than a certain cutoff.
133 *
134 * @param cutoffInstant The cutoff time threshold since the epoch (00:00:00 GMT, January 1, 1970).
135 * @since 2.12.0
136 */
137 public AgeFileFilter(final Instant cutoffInstant) {
138 this(cutoffInstant, true);
139 }
140
141 /**
142 * Constructs a new age file filter for files on any one side of a certain cutoff.
143 *
144 * @param cutoffInstant The cutoff time threshold since the epoch (00:00:00 GMT, January 1, 1970).
145 * @param acceptOlder if true, older files (at or before the cutoff) are accepted, else newer ones (after the cutoff).
146 * @since 2.12.0
147 */
148 public AgeFileFilter(final Instant cutoffInstant, final boolean acceptOlder) {
149 this.acceptOlder = acceptOlder;
150 this.cutoffInstant = cutoffInstant;
151 }
152
153 /**
154 * Constructs a new age file filter for files equal to or older than a certain cutoff
155 *
156 * @param cutoffMillis The cutoff time threshold measured in milliseconds since the epoch (00:00:00 GMT, January 1,
157 * 1970).
158 */
159 public AgeFileFilter(final long cutoffMillis) {
160 this(Instant.ofEpochMilli(cutoffMillis), true);
161 }
162
163 /**
164 * Constructs a new age file filter for files on any one side of a certain cutoff.
165 *
166 * @param cutoffMillis The cutoff time threshold measured in milliseconds since the epoch (00:00:00 GMT, January 1,
167 * 1970).
168 * @param acceptOlder if true, older files (at or before the cutoff) are accepted, else newer ones (after the
169 * cutoff).
170 */
171 public AgeFileFilter(final long cutoffMillis, final boolean acceptOlder) {
172 this(Instant.ofEpochMilli(cutoffMillis), acceptOlder);
173 }
174
175 /**
176 * Tests to see if the last modification of the file matches cutoff favorably.
177 * <p>
178 * If last modification time equals cutoff and newer files are required, file <strong>IS NOT</strong> selected. If last
179 * modification time equals cutoff and older files are required, file <strong>IS</strong> selected.
180 * </p>
181 *
182 * @param file the File to check.
183 * @return true if the file name matches.
184 */
185 @Override
186 public boolean accept(final File file) {
187 return acceptOlder != FileUtils.isFileNewer(file, cutoffInstant);
188 }
189
190 /**
191 * Tests to see if the last modification of the file matches cutoff favorably.
192 * <p>
193 * If last modification time equals cutoff and newer files are required, file <strong>IS NOT</strong> selected. If last
194 * modification time equals cutoff and older files are required, file <strong>IS</strong> selected.
195 * </p>
196 *
197 * @param file the File to check.
198 * @param attributes the path's basic attributes (may be null).
199 * @return true if the file name matches.
200 * @since 2.9.0
201 */
202 @Override
203 public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) {
204 return get(() -> toFileVisitResult(acceptOlder != PathUtils.isNewer(file, cutoffInstant)));
205 }
206
207 /**
208 * Provide a String representation of this file filter.
209 *
210 * @return a String representation.
211 */
212 @Override
213 public String toString() {
214 final String condition = acceptOlder ? "<=" : ">";
215 return super.toString() + "(" + condition + cutoffInstant + ")";
216 }
217 }