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.Files;
023import java.nio.file.Path;
024import java.nio.file.attribute.BasicFileAttributes;
025import java.util.stream.Stream;
026
027import org.apache.commons.io.IOUtils;
028
029/**
030 * This filter accepts files or directories that are empty.
031 * <p>
032 * If the {@link File} is a directory it checks that it contains no files.
033 * </p>
034 * <p>
035 * Example, showing how to print out a list of the current directory's empty files/directories:
036 * </p>
037 * <h2>Using Classic IO</h2>
038 * <pre>
039 * File dir = FileUtils.current();
040 * String[] files = dir.list(EmptyFileFilter.EMPTY);
041 * for (String file : files) {
042 *     System.out.println(file);
043 * }
044 * </pre>
045 *
046 * <p>
047 * Example, showing how to print out a list of the current directory's non-empty files/directories:
048 * </p>
049 *
050 * <pre>
051 * File dir = FileUtils.current();
052 * String[] files = dir.list(EmptyFileFilter.NOT_EMPTY);
053 * for (String file : files) {
054 *     System.out.println(file);
055 * }
056 * </pre>
057 *
058 * <h2>Using NIO</h2>
059 * <pre>
060 * final Path dir = PathUtils.current();
061 * final AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(EmptyFileFilter.EMPTY);
062 * //
063 * // Walk one dir
064 * Files.<b>walkFileTree</b>(dir, Collections.emptySet(), 1, visitor);
065 * System.out.println(visitor.getPathCounters());
066 * System.out.println(visitor.getFileList());
067 * //
068 * visitor.getPathCounters().reset();
069 * //
070 * // Walk dir tree
071 * Files.<b>walkFileTree</b>(dir, visitor);
072 * System.out.println(visitor.getPathCounters());
073 * System.out.println(visitor.getDirList());
074 * System.out.println(visitor.getFileList());
075 * </pre>
076 * <h2>Deprecating Serialization</h2>
077 * <p>
078 * <em>Serialization is deprecated and will be removed in 3.0.</em>
079 * </p>
080 *
081 * @since 1.3
082 */
083public class EmptyFileFilter extends AbstractFileFilter implements Serializable {
084
085    /** Singleton instance of <i>empty</i> filter */
086    public static final IOFileFilter EMPTY = new EmptyFileFilter();
087
088    /** Singleton instance of <i>not-empty</i> filter */
089    public static final IOFileFilter NOT_EMPTY = EMPTY.negate();
090
091    private static final long serialVersionUID = 3631422087512832211L;
092
093    /**
094     * Restrictive constructor.
095     */
096    protected EmptyFileFilter() {
097    }
098
099    /**
100     * Checks to see if the file is empty.
101     *
102     * @param file the file or directory to check
103     * @return {@code true} if the file or directory is <i>empty</i>, otherwise {@code false}.
104     */
105    @Override
106    public boolean accept(final File file) {
107        if (file.isDirectory()) {
108            final File[] files = file.listFiles();
109            return IOUtils.length(files) == 0;
110        }
111        return file.length() == 0;
112    }
113
114    /**
115     * Checks to see if the file is empty.
116     * @param file the file or directory to check
117     *
118     * @return {@code true} if the file or directory is <i>empty</i>, otherwise {@code false}.
119     * @since 2.9.0
120     */
121    @Override
122    public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) {
123        return get(() -> {
124            if (Files.isDirectory(file)) {
125                try (Stream<Path> stream = Files.list(file)) {
126                    return toFileVisitResult(!stream.findFirst().isPresent());
127                }
128            }
129            return toFileVisitResult(Files.size(file) == 0);
130        });
131    }
132
133}