All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.alipay.rdf.file.util.FileNameUtils Maven / Gradle / Ivy

There is a newer version: 2.2.11
Show newest version
package com.alipay.rdf.file.util;

import java.io.File;

/**
 * Copyright (C) 2013-2018 Ant Financial Services Group
 *
 * @author hongwei.quhw
 * @version $Id: FileNameUtils.java, v 0.1 2018年3月12日 下午4:29:22 hongwei.quhw Exp $
 */
public class FileNameUtils {
    public static final String EMPTY             = "";
    /**
     * The Unix separator character.
     */
    private static final char  UNIX_SEPARATOR    = '/';

    /**
     * The Windows separator character.
     */
    private static final char  WINDOWS_SEPARATOR = '\\';

    /**
     * The system separator character.
     */
    private static final char  SYSTEM_SEPARATOR  = File.separatorChar;

    /**
     * The separator character that is the opposite of the system separator.
     */
    private static final char  OTHER_SEPARATOR;

    static {
        if (isSystemWindows()) {
            OTHER_SEPARATOR = UNIX_SEPARATOR;
        } else {
            OTHER_SEPARATOR = WINDOWS_SEPARATOR;
        }
    }

    /**
     * Determines if Windows file system is in use.
     * 
     * @return true if the system is Windows
     */
    static boolean isSystemWindows() {
        return SYSTEM_SEPARATOR == WINDOWS_SEPARATOR;
    }

    /**
     * Normalizes a path, removing double and single dot path steps.
     * 

* This method normalizes a path to a standard format. * The input may contain separators in either Unix or Windows format. * The output will contain separators in the format of the system. *

* A trailing slash will be retained. * A double slash will be merged to a single slash (but UNC names are handled). * A single dot path segment will be removed. * A double dot will cause that path segment and the one before to be removed. * If the double dot has no parent path segment to work with, {@code null} * is returned. *

* The output will be the same on both Unix and Windows except * for the separator character. *

     * /foo//               -->   /foo/
     * /foo/./              -->   /foo/
     * /foo/../bar          -->   /bar
     * /foo/../bar/         -->   /bar/
     * /foo/../bar/../baz   -->   /baz
     * //foo//./bar         -->   /foo/bar
     * /../                 -->   null
     * ../foo               -->   null
     * foo/bar/..           -->   foo/
     * foo/../../bar        -->   null
     * foo/../bar           -->   bar
     * //server/foo/../bar  -->   //server/bar
     * //server/../bar      -->   null
     * C:\foo\..\bar        -->   C:\bar
     * C:\..\bar            -->   null
     * ~/foo/../bar/        -->   ~/bar/
     * ~/../bar             -->   null
     * 
* (Note the file separator returned will be correct for Windows/Unix) * * @param filename the filename to normalize, null returns null * @return the normalized filename, or null if invalid */ public static String normalize(String filename) { return doNormalize(filename, SYSTEM_SEPARATOR, true); } /** * Internal method to perform the normalization. * * @param filename the filename * @param separator The separator character to use * @param keepSeparator true to keep the final separator * @return the normalized filename */ private static String doNormalize(String filename, char separator, boolean keepSeparator) { if (filename == null) { return null; } int size = filename.length(); if (size == 0) { return filename; } int prefix = getPrefixLength(filename); if (prefix < 0) { return null; } char[] array = new char[size + 2]; // +1 for possible extra slash, +2 for arraycopy filename.getChars(0, filename.length(), array, 0); // fix separators throughout char otherSeparator = separator == SYSTEM_SEPARATOR ? OTHER_SEPARATOR : SYSTEM_SEPARATOR; for (int i = 0; i < array.length; i++) { if (array[i] == otherSeparator) { array[i] = separator; } } // add extra separator on the end to simplify code below boolean lastIsDirectory = true; if (array[size - 1] != separator) { array[size++] = separator; lastIsDirectory = false; } // adjoining slashes for (int i = prefix + 1; i < size; i++) { if (array[i] == separator && array[i - 1] == separator) { System.arraycopy(array, i, array, i - 1, size - i); size--; i--; } } // dot slash for (int i = prefix + 1; i < size; i++) { if (array[i] == separator && array[i - 1] == '.' && (i == prefix + 1 || array[i - 2] == separator)) { if (i == size - 1) { lastIsDirectory = true; } System.arraycopy(array, i + 1, array, i - 1, size - i); size -= 2; i--; } } // double dot slash outer: for (int i = prefix + 2; i < size; i++) { if (array[i] == separator && array[i - 1] == '.' && array[i - 2] == '.' && (i == prefix + 2 || array[i - 3] == separator)) { if (i == prefix + 2) { return null; } if (i == size - 1) { lastIsDirectory = true; } int j; for (j = i - 4; j >= prefix; j--) { if (array[j] == separator) { // remove b/../ from a/b/../c System.arraycopy(array, i + 1, array, j + 1, size - i); size -= i - j; i = j + 1; continue outer; } } // remove a/../ from a/../c System.arraycopy(array, i + 1, array, prefix, size - i); size -= i + 1 - prefix; i = prefix + 1; } } if (size <= 0) { // should never be less than 0 return ""; } if (size <= prefix) { // should never be less than prefix return new String(array, 0, size); } if (lastIsDirectory && keepSeparator) { return new String(array, 0, size); // keep trailing separator } return new String(array, 0, size - 1); // lose trailing separator } /** * Returns the length of the filename prefix, such as C:/ or ~/. *

* This method will handle a file in either Unix or Windows format. *

* The prefix length includes the first slash in the full filename * if applicable. Thus, it is possible that the length returned is greater * than the length of the input string. *

     * Windows:
     * a\b\c.txt           --> ""          --> relative
     * \a\b\c.txt          --> "\"         --> current drive absolute
     * C:a\b\c.txt         --> "C:"        --> drive relative
     * C:\a\b\c.txt        --> "C:\"       --> absolute
     * \\server\a\b\c.txt  --> "\\server\" --> UNC
     *
     * Unix:
     * a/b/c.txt           --> ""          --> relative
     * /a/b/c.txt          --> "/"         --> absolute
     * ~/a/b/c.txt         --> "~/"        --> current user
     * ~                   --> "~/"        --> current user (slash added)
     * ~user/a/b/c.txt     --> "~user/"    --> named user
     * ~user               --> "~user/"    --> named user (slash added)
     * 
*

* The output will be the same irrespective of the machine that the code is running on. * ie. both Unix and Windows prefixes are matched regardless. * * @param filename the filename to find the prefix in, null returns -1 * @return the length of the prefix, -1 if invalid or null */ public static int getPrefixLength(String filename) { if (filename == null) { return -1; } int len = filename.length(); if (len == 0) { return 0; } char ch0 = filename.charAt(0); if (ch0 == ':') { return -1; } if (len == 1) { if (ch0 == '~') { return 2; // return a length greater than the input } return isSeparator(ch0) ? 1 : 0; } else { if (ch0 == '~') { int posUnix = filename.indexOf(UNIX_SEPARATOR, 1); int posWin = filename.indexOf(WINDOWS_SEPARATOR, 1); if (posUnix == -1 && posWin == -1) { return len + 1; // return a length greater than the input } posUnix = posUnix == -1 ? posWin : posUnix; posWin = posWin == -1 ? posUnix : posWin; return Math.min(posUnix, posWin) + 1; } char ch1 = filename.charAt(1); if (ch1 == ':') { ch0 = Character.toUpperCase(ch0); if (ch0 >= 'A' && ch0 <= 'Z') { if (len == 2 || isSeparator(filename.charAt(2)) == false) { return 2; } return 3; } return -1; } else if (isSeparator(ch0) && isSeparator(ch1)) { int posUnix = filename.indexOf(UNIX_SEPARATOR, 2); int posWin = filename.indexOf(WINDOWS_SEPARATOR, 2); if (posUnix == -1 && posWin == -1 || posUnix == 2 || posWin == 2) { return -1; } posUnix = posUnix == -1 ? posWin : posUnix; posWin = posWin == -1 ? posUnix : posWin; return Math.min(posUnix, posWin) + 1; } else { return isSeparator(ch0) ? 1 : 0; } } } /** * Checks if the character is a separator. * * @param ch the character to check * @return true if it is a separator character */ private static boolean isSeparator(char ch) { return ch == UNIX_SEPARATOR || ch == WINDOWS_SEPARATOR; } public static String join(Object[] array, String separator) { if (array == null) { return null; } return join(array, separator, 0, array.length); } public static String join(Object[] array, String separator, int startIndex, int endIndex) { if (array == null) { return null; } if (separator == null) { separator = EMPTY; } // endIndex - startIndex > 0: Len = NofStrings *(len(firstString) + len(separator)) // (Assuming that all Strings are roughly equally long) int bufSize = (endIndex - startIndex); if (bufSize <= 0) { return EMPTY; } bufSize *= ((array[startIndex] == null ? 16 : array[startIndex].toString().length()) + separator.length()); StringBuilder buf = new StringBuilder(bufSize); for (int i = startIndex; i < endIndex; i++) { if (i > startIndex) { buf.append(separator); } if (array[i] != null) { buf.append(array[i]); } } return buf.toString(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy