?? filenameutils.java
字號:
/*
* Copyright 2001-2005 The Apache Software Foundation.
*
* 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 org.apache.commons.io;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Stack;
/**
* General filename and filepath manipulation utilities.
* <p>
* When dealing with filenames you can hit problems when moving from a Windows
* based development machine to a Unix based production machine.
* This class aims to help avoid those problems.
* <p>
* <b>NOTE</b>: You may be able to avoid using this class entirely simply by
* using JDK {@link java.io.File File} objects and the two argument constructor
* {@link java.io.File#File(java.io.File, java.lang.String) File(File,String)}.
* <p>
* Most methods on this class are designed to work the same on both Unix and Windows.
* Those that don't include 'System', 'Unix' or 'Windows' in their name.
* <p>
* Most methods recognise both separators (forward and back), and both
* sets of prefixes. See the javadoc of each method for details.
* <p>
* This class defines six components within a filename
* (example C:\dev\project\file.txt):
* <ul>
* <li>the prefix - C:\</li>
* <li>the path - dev\project\</li>
* <li>the full path - C:\dev\project\</li>
* <li>the name - file.txt</li>
* <li>the base name - file</li>
* <li>the extension - txt</li>
* </ul>
* Note that this class works best if directory filenames end with a separator.
* If you omit the last separator, it is impossible to determine if the filename
* corresponds to a file or a directory. As a result, we have chosen to say
* it corresponds to a file.
* <p>
* This class only supports Unix and Windows style names.
* Prefixes are matched as follows:
* <pre>
* 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)
* </pre>
* Both prefix styles are matched always, irrespective of the machine that you are
* currently running on.
* <p>
* Origin of code: Excalibur, Alexandria, Tomcat, Commons-Utils.
*
* @author <a href="mailto:burton@relativity.yi.org">Kevin A. Burton</A>
* @author <a href="mailto:sanders@apache.org">Scott Sanders</a>
* @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
* @author <a href="mailto:Christoph.Reck@dlr.de">Christoph.Reck</a>
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
* @author <a href="mailto:jefft@apache.org">Jeff Turner</a>
* @author Matthew Hawthorne
* @author Martin Cooper
* @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a>
* @author Stephen Colebourne
* @version $Id: FilenameUtils.java 289999 2005-09-18 23:12:45Z scolebourne $
* @since Commons IO 1.1
*/
public class FilenameUtils {
/**
* The extension separator character.
*/
private static final char EXTENSION_SEPARATOR = '.';
/**
* 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 (SYSTEM_SEPARATOR == WINDOWS_SEPARATOR) {
OTHER_SEPARATOR = UNIX_SEPARATOR;
} else {
OTHER_SEPARATOR = WINDOWS_SEPARATOR;
}
}
/**
* Instances should NOT be constructed in standard programming.
*/
public FilenameUtils() {
super();
}
//-----------------------------------------------------------------------
/**
* 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);
}
//-----------------------------------------------------------------------
/**
* Normalizes a path, removing double and single dot path steps.
* <p>
* 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.
* <p>
* 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</code>
* is returned.
* <p>
* The output will be the same on both Unix and Windows except
* for the separator character.
* <pre>
* /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
* </pre>
* (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, true);
}
//-----------------------------------------------------------------------
/**
* Normalizes a path, removing double and single dot path steps,
* and removing any final directory separator.
* <p>
* 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.
* <p>
* A trailing slash will be removed.
* 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</code>
* is returned.
* <p>
* The output will be the same on both Unix and Windows except
* for the separator character.
* <pre>
* /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
* </pre>
* (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 normalizeNoEndSeparator(String filename) {
return doNormalize(filename, false);
}
/**
* Internal method to perform the normalization.
*
* @param filename the filename
* @param keepSeparator true to keep the final separator
* @return the normalized filename
*/
private static String doNormalize(String filename, 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
for (int i = 0; i < array.length; i++) {
if (array[i] == OTHER_SEPARATOR) {
array[i] = SYSTEM_SEPARATOR;
}
}
// add extra separator on the end to simplify code below
boolean lastIsDirectory = true;
if (array[size - 1] != SYSTEM_SEPARATOR) {
array[size++] = SYSTEM_SEPARATOR;
lastIsDirectory = false;
}
// adjoining slashes
for (int i = prefix + 1; i < size; i++) {
if (array[i] == SYSTEM_SEPARATOR && array[i - 1] == SYSTEM_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] == SYSTEM_SEPARATOR && array[i - 1] == '.' &&
(i == prefix + 1 || array[i - 2] == SYSTEM_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] == SYSTEM_SEPARATOR && array[i - 1] == '.' && array[i - 2] == '.' &&
(i == prefix + 2 || array[i - 3] == SYSTEM_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] == SYSTEM_SEPARATOR) {
// remove b/../ from a/b/../c
System.arraycopy(array, i + 1, array, j + 1, size - i);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -