co.cask.cdap.common.utils.DirUtils.java Source code

Java tutorial

Introduction

Here is the source code for co.cask.cdap.common.utils.DirUtils.java

Source

/*
 * Copyright  2014 Cask Data, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package co.cask.cdap.common.utils;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.Files;

import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
import javax.annotation.Nullable;

/**
 * Provides utility methods for operating on directories.
 */
public final class DirUtils {

    private static final int TEMP_DIR_ATTEMPTS = 10000;

    /**
     * Utility classes should have a public constructor or a default constructor
     * hence made it private.
     */
    private DirUtils() {
    }

    /**
     * Same as calling {@link #deleteDirectoryContents(File, boolean) deleteDirectoryContents(directory, false)}.
     */
    public static void deleteDirectoryContents(File directory) throws IOException {
        deleteDirectoryContents(directory, false);
    }

    /**
     * Wipes out content of a directory starting from a given directory.
     *
     * @param directory to be cleaned
     * @param retain if true, the given directory will be retained.
     * @throws IOException
     */
    public static void deleteDirectoryContents(File directory, boolean retain) throws IOException {
        if (!directory.isDirectory()) {
            throw new IOException("Not a directory: " + directory);
        }

        // avoid using guava's Queues.newArrayDeque() since this is a utility class that can be used in all sorts of
        // contexts, some of which may use clashing guava versions... For example, when explore launches a Hive query,
        // it includes hive-exec.jar which bundles guava 11 in its jar...
        Deque<File> stack = new ArrayDeque<>();
        stack.addAll(listFiles(directory));

        while (!stack.isEmpty()) {
            File file = stack.peekLast();
            List<File> files = listFiles(file);
            if (files.isEmpty()) {
                if (!file.delete()) {
                    throw new IOException("Failed to delete file " + file);
                }
                stack.pollLast();
            } else {
                stack.addAll(files);
            }
        }

        if (!retain) {
            if (!directory.delete()) {
                throw new IOException("Failed to delete directory " + directory);
            }
        }
    }

    /**
     * Creates a temp directory inside the given base directory.
     *
     * @return the newly-created directory
     * @throws IllegalStateException if the directory could not be created
     */
    public static File createTempDir(File baseDir) {
        String baseName = System.currentTimeMillis() + "-";

        for (int counter = 0; counter < TEMP_DIR_ATTEMPTS; counter++) {
            File tempDir = new File(baseDir, baseName + counter);
            if (tempDir.mkdirs()) {
                return tempDir;
            }
        }
        throw new IllegalStateException("Failed to create directory within " + TEMP_DIR_ATTEMPTS
                + " attempts (tried " + baseName + "0 to " + baseName + (TEMP_DIR_ATTEMPTS - 1) + ')');
    }

    /**
     * Creates a directory if the directory doesn't exists.
     *
     * @param dir The directory to create
     * @return {@code true} if the directory exists or successfully created the directory.
     */
    public static boolean mkdirs(File dir) {
        // The last clause is needed so that if there are multiple threads trying to create the same directory
        // this method will still return true.
        return dir.isDirectory() || dir.mkdirs() || dir.isDirectory();
    }

    /**
     * Returns list of file names under the given directory. An empty list will be returned if the given file is
     * not a directory.
     */
    public static List<String> list(File directory) {
        return listOf(directory.list());
    }

    /**
     * Returns list of file names under the given directory that are accepted by the given filter.
     * An empty list will be returned if the given file is not a directory.
     */
    public static List<String> list(File directory, FilenameFilter filenameFilter) {
        return listOf(directory.list(filenameFilter));
    }

    /**
     * Returns list of file names under the given directory that matches the give set of file name extension.
     * An empty list will be returned if the given file is not a directory.
     */
    public static List<String> list(File directory, String... extensions) {
        return list(directory, ImmutableSet.copyOf(extensions));
    }

    /**
     * Returns list of file names under the given directory that matches the give set of file name extension.
     * An empty list will be returned if the given file is not a directory.
     */
    public static List<String> list(File directory, Iterable<String> extensions) {
        final ImmutableSet<String> allowedExtensions = ImmutableSet.copyOf(extensions);

        return list(directory, new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return allowedExtensions.contains(Files.getFileExtension(name));
            }
        });
    }

    /**
     * Returns list of files under the given directory. An empty list will be returned if the
     * given file is not a directory.
     */
    public static List<File> listFiles(File directory) {
        return listOf(directory.listFiles());
    }

    /**
     * Returns list of files under the given directory that are accepted by the given filter.
     * An empty list will be returned if the given file is not a directory.
     */
    public static List<File> listFiles(File directory, FileFilter fileFilter) {
        return listOf(directory.listFiles(fileFilter));
    }

    /**
     * Returns list of files under the given directory that are accepted by the given filter.
     * An empty list will be returned if the given file is not a directory.
     */
    public static List<File> listFiles(File directory, FilenameFilter filenameFilter) {
        return listOf(directory.listFiles(filenameFilter));
    }

    /**
     * Returns list of files under the given directory that matches the give set of file name extension.
     * An empty list will be returned if the given file is not a directory.
     */
    public static List<File> listFiles(File directory, String... extensions) {
        return listFiles(directory, ImmutableSet.copyOf(extensions));
    }

    /**
     * Returns list of files under the given directory that matches the give set of file name extension.
     * An empty list will be returned if the given file is not a directory.
     */
    public static List<File> listFiles(File directory, Iterable<String> extensions) {
        final ImmutableSet<String> allowedExtensions = ImmutableSet.copyOf(extensions);

        return listFiles(directory, new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return allowedExtensions.contains(Files.getFileExtension(name));
            }
        });
    }

    /**
     * Converts the given array into a list. An empty list will be returned if the given array is {@code null}.
     * (Note: This method might worth to be in some other common class, which we don't have now).
     *
     * @param elements array to convert
     * @param <T> type of elements in the array
     * @return a new immutable list.
     */
    private static <T> List<T> listOf(@Nullable T[] elements) {
        return elements == null ? ImmutableList.<T>of() : ImmutableList.copyOf(elements);
    }
}