PathUtil.java

/*
 * Copyright (c) 2017, Stein Eldar Johnsen
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you 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 net.morimekta.file;

import java.nio.file.Path;
import java.util.Optional;

import static java.util.Objects.requireNonNull;

/**
 * Utility for helping with file names and paths.
 */
public final class PathUtil {
    /**
     * Get the base name of a file, which is the file name without its suffix.
     * The suffix is separated from the base name by the last single {@code '.'}
     * in the file name. Consecutive dots are not treated as a suffix separator,
     * so {@code "test..file"} has no suffix and the entire string is the base
     * name. A leading {@code "."} or {@code ".."} is not treated as a suffix
     * separator either (e.g. {@code ".gitignore"} has base name
     * {@code ".gitignore"}).
     *
     * @param path The file path.
     * @return The file name without suffix.
     * @see #getFileSuffix(Path)
     */
    public static String getFileBaseName(Path path) {
        return getFileBaseName(getFileName(path));
    }

    /**
     * Get the base name of a file, which is the file name without its suffix.
     * See {@link #getFileBaseName(Path)} for the rules on suffix detection.
     *
     * @param fileName The file name. If it contains {@code '/'} (path separator),
     *                 the result is undefined.
     * @return The file name without suffix.
     */
    public static String getFileBaseName(String fileName) {
        requireNonNull(fileName, "fileName == null");
        int dot = fileName.lastIndexOf('.');
        if (dot > 0 && fileName.charAt(dot - 1) == '.') {
            return fileName;
        }
        if (dot > 0) {
            return fileName.substring(0, dot);
        }
        return fileName;
    }

    /**
     * Get the file suffix, which is the part after the last single {@code '.'}
     * in the file name. Returns an empty string if there is no suffix. For
     * example, {@code "image.png"} has suffix {@code "png"}, while
     * {@code ".gitignore"} and {@code "test..file"} have no suffix.
     *
     * @param path The file path.
     * @return The suffix, or an empty string if none.
     * @see #getFileBaseName(Path)
     */
    public static String getFileSuffix(Path path) {
        return getFileSuffix(getFileName(path));
    }

    /**
     * Get the file suffix. See {@link #getFileSuffix(Path)} for the suffix
     * detection rules.
     *
     * @param fileName The file name. If it contains {@code '/'} (path separator),
     *                 the result is undefined.
     * @return The suffix, or an empty string if none.
     */
    public static String getFileSuffix(String fileName) {
        requireNonNull(fileName, "fileName == null");
        int dot = fileName.lastIndexOf('.');
        if (dot > 0 && fileName.charAt(dot - 1) == '.') {
            return "";
        }
        if (dot > 0) {
            return fileName.substring(dot + 1);
        }
        return "";
    }

    /**
     * Get the file name component of a path. Returns an empty string for
     * root paths or paths that have no file name element.
     *
     * @param path The file path.
     * @return The file name, or an empty string.
     */
    public static String getFileName(Path path) {
        requireNonNull(path, "path == null");
        return Optional.ofNullable(path.getFileName())
                       .map(Path::toString)
                       .orElse("");
    }

    private PathUtil() {}
}