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