scolebourne 2004/12/04 11:28:40 Modified: io/src/test/org/apache/commons/io FilenameUtilsTestCase.java io/src/java/org/apache/commons/io FilenameUtils.java Log: Add equals methods, document Unix/Windows behaviour Revision Changes Path 1.23 +23 -1 jakarta-commons/io/src/test/org/apache/commons/io/FilenameUtilsTestCase.java Index: FilenameUtilsTestCase.java =================================================================== RCS file: /home/cvs/jakarta-commons/io/src/test/org/apache/commons/io/FilenameUtilsTestCase.java,v retrieving revision 1.22 retrieving revision 1.23 diff -u -r1.22 -r1.23 --- FilenameUtilsTestCase.java 27 Nov 2004 17:00:51 -0000 1.22 +++ FilenameUtilsTestCase.java 4 Dec 2004 19:28:40 -0000 1.23 @@ -451,6 +451,28 @@ } //----------------------------------------------------------------------- + public void testEquals() { + assertEquals(true, FilenameUtils.equals(null, null)); + assertEquals(false, FilenameUtils.equals(null, "")); + assertEquals(false, FilenameUtils.equals("", null)); + assertEquals(true, FilenameUtils.equals("", "")); + assertEquals(true, FilenameUtils.equals("file.txt", "file.txt")); + assertEquals(WINDOWS, FilenameUtils.equals("file.txt", "FILE.TXT")); + assertEquals(false, FilenameUtils.equals("a\\b\\file.txt", "a/b/file.txt")); + } + + public void testEqualsNormalized() { + assertEquals(true, FilenameUtils.equalsNormalized(null, null)); + assertEquals(false, FilenameUtils.equalsNormalized(null, "")); + assertEquals(false, FilenameUtils.equalsNormalized("", null)); + assertEquals(true, FilenameUtils.equalsNormalized("", "")); + assertEquals(true, FilenameUtils.equalsNormalized("file.txt", "file.txt")); + assertEquals(WINDOWS, FilenameUtils.equalsNormalized("file.txt", "FILE.TXT")); + assertEquals(true, FilenameUtils.equalsNormalized("a\\b\\file.txt", "a/b/file.txt")); + assertEquals(true, FilenameUtils.equalsNormalized("a\\b\\", "a/b")); + } + + //----------------------------------------------------------------------- public void testIsExtension() { assertEquals(false, FilenameUtils.isExtension(null, (String) null)); assertEquals(false, FilenameUtils.isExtension("file.txt", (String) null)); 1.31 +134 -26 jakarta-commons/io/src/java/org/apache/commons/io/FilenameUtils.java Index: FilenameUtils.java =================================================================== RCS file: /home/cvs/jakarta-commons/io/src/java/org/apache/commons/io/FilenameUtils.java,v retrieving revision 1.30 retrieving revision 1.31 diff -u -r1.30 -r1.31 --- FilenameUtils.java 27 Nov 2004 17:00:51 -0000 1.30 +++ FilenameUtils.java 4 Dec 2004 19:28:40 -0000 1.31 @@ -22,6 +22,16 @@ /** * Utility class that provides methods to manipulate filenames and filepaths. * <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> + * Most methods on this class are designed to work the same on both Unix and Windows. + * Both separators (forward and back) are recognised, and both sets of prefixes. + * The comparison methods do differ by machine however, comparing case insensitive + * on Windows and case sensitive on Unix. + * 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> @@ -31,7 +41,9 @@ * <li>the base name - file</li> * <li>the extension - txt</li> * </ul> - * The class only supports Unix and Windows style names. Prefixes are matched as follows: + * Note that the path of a directory is the parent directory. + * <p> + * This class only supports Unix and Windows style names. Prefixes are matched as follows: * <pre> * Windows style: * a\b\c.txt --> "" --> relative @@ -45,6 +57,8 @@ * ~/a/b/c.txt --> "~/" --> current user relative * ~user/a/b/c.txt --> "~user/" --> named user relative * </pre> + * Both prefix styles are matched always, irrespective of the machine that you are + * currently running on. * * </p> * <h3>Origin of code</h3> @@ -133,6 +147,9 @@ * 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 @@ -151,7 +168,7 @@ * ~/foo/../bar --> ~/bar * ~/../bar --> null * </pre> - * (Note the file separator returned will be correct for windows/unix) + * (Note the file separator returned will be correct for Windows/Unix) * * @param filename the filename to normalize, null returns null * @return the normalized String, or null if invalid @@ -232,7 +249,7 @@ } /** - * Concatenates two paths using normal command line style rules. + * Concatenates a filename to a base path using normal command line style rules. * <p> * The first argument is the base path, the second is the path to concatenate. * The returned path is always normalized via [EMAIL PROTECTED] #normalize(String)}, @@ -241,43 +258,47 @@ * If <code>pathToAdd</code> is absolute (has a prefix), then it will * be normalized and returned. * Otherwise, the paths will be joined, normalized and returned. + * <p> + * The output will be the same on both Unix and Windows except + * for the separator character. * <pre> * /foo/ + bar --> /foo/bar * /foo/a + bar --> /foo/a/bar - * /foo/c.txt + bar --> /foo/c.txt/bar * /foo/ + ../bar --> /bar * /foo/ + ../../bar --> null * /foo/ + /bar --> /bar * /foo/.. + /bar --> /bar + * /foo + bar/c.txt --> /foo/bar/c.txt + * /foo/c.txt + bar --> /foo/c.txt/bar (!) * </pre> - * Note that the first parameter must be a path. If it ends with a name, then + * (!) Note that the first parameter must be a path. If it ends with a name, then * the name will be built into the concatenated path. If this might be a problem, * use [EMAIL PROTECTED] #getFullPath(String)} on the base path argument. * * @param basePath the base path to attach to, always treated as a path - * @param pathToAdd path the second path to attach to the first + * @param fullFilenameToAdd the filename (or path) to attach to the base * @return the concatenated path, or null if invalid */ - public static String concat(String basePath, String pathToAdd) { - int prefix = getPrefixLength(pathToAdd); + public static String concat(String basePath, String fullFilenameToAdd) { + int prefix = getPrefixLength(fullFilenameToAdd); if (prefix < 0) { return null; } if (prefix > 0) { - return normalize(pathToAdd); + return normalize(fullFilenameToAdd); } if (basePath == null) { return null; } int len = basePath.length(); if (len == 0) { - return normalize(pathToAdd); + return normalize(fullFilenameToAdd); } char ch = basePath.charAt(len - 1); if (isSeparator(basePath.charAt(len - 1))) { - return normalize(basePath + pathToAdd); + return normalize(basePath + fullFilenameToAdd); } else { - return normalize(basePath + '/' + pathToAdd); + return normalize(basePath + '/' + fullFilenameToAdd); } } @@ -344,8 +365,9 @@ * ~/a/b/c.txt --> "~/" --> current user relative * ~user/a/b/c.txt --> "~user/" --> named user relative * </pre> - * Both sets of prefixes will be matched regardless of the system - * on which the code runs. + * <p> + * 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 @@ -406,6 +428,8 @@ * <p> * This method will handle a file in either Unix or Windows format. * The position of the last forward or backslash is returned. + * <p> + * The output will be the same irrespective of the machine that the code is running on. * * @param filename the filename to find the last path separator in, null returns -1 * @return the index of the last separator character, or -1 if there @@ -426,6 +450,8 @@ * This method also checks that there is no directory separator after the last dot. * To do this it uses [EMAIL PROTECTED] #indexOfLastSeparator(String)} which will * handle a file in either Unix or Windows format. + * <p> + * The output will be the same irrespective of the machine that the code is running on. * * @param filename the filename to find the last path separator in, null returns -1 * @return the index of the last separator character, or -1 if there @@ -459,6 +485,9 @@ * ~/a/b/c.txt --> "~/" --> current user relative * ~user/a/b/c.txt --> "~user/" --> named user relative * </pre> + * <p> + * 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 query, null returns null * @return the prefix of the file, null if invalid @@ -476,6 +505,7 @@ /** * Gets the path from a full filename, which excludes the prefix. + * The path of a directory is the parent directory. * <p> * This method will handle a file in either Unix or Windows format. * The text before the last forward or backslash is returned. @@ -486,6 +516,8 @@ * a/b/c --> a/b * a/b/c/ --> a/b/c * </pre> + * <p> + * The output will be the same irrespective of the machine that the code is running on. * * @param filename the filename to query, null returns null * @return the path of the file, an empty string if none exists, null if invalid @@ -508,6 +540,7 @@ /** * Gets the full path from a full filename, which is the prefix + path. + * The path of a directory is the parent directory. * <p> * This method will handle a file in either Unix or Windows format. * The text before the last forward or backslash is returned. @@ -518,6 +551,8 @@ * a/b/c --> a/b * a/b/c/ --> a/b/c * </pre> + * <p> + * The output will be the same irrespective of the machine that the code is running on. * * @param filename the filename to query, null returns null * @return the path of the file, an empty string if none exists, null if invalid @@ -549,6 +584,8 @@ * a/b/c --> c * a/b/c/ --> "" * </pre> + * <p> + * The output will be the same irrespective of the machine that the code is running on. * * @param filename the filename to query, null returns null * @return the name of the file without the path, or an empty string if none exists @@ -572,6 +609,8 @@ * a/b/c --> c * a/b/c/ --> "" * </pre> + * <p> + * The output will be the same irrespective of the machine that the code is running on. * * @param filename the filename to query, null returns null * @return the name of the file without the path, or an empty string if none exists @@ -591,6 +630,8 @@ * a/b.txt/c --> "" * a/b/c --> "" * </pre> + * <p> + * The output will be the same irrespective of the machine that the code is running on. * * @param filename the filename to retrieve the extension of. * @return the extension of the file or an empty string if none exists. @@ -615,10 +656,12 @@ * There must be no directory separator after the dot. * <pre> * foo.txt --> foo - * a\b\c.jpg --> a\b\c - * a\b\c --> a\b\c - * a.b\c --> a.b\c + * a\b\c.jpg --> a\b\c + * a\b\c --> a\b\c + * a.b\c --> a.b\c * </pre> + * <p> + * The output will be the same irrespective of the machine that the code is running on. * * @param filename the filename to query, null returns null * @return the filename minus the extension @@ -637,7 +680,60 @@ //----------------------------------------------------------------------- /** - * Checks whether the extension of the filename is that specified. + * Checks whether two filenames are equal using the case rules of the system. + * <p> + * No processing is performed on the filenames other than comparison. + * The check is case sensitive on Unix and case insensitive on Windows. + * + * @param filename1 the first filename to query, may be null + * @param filename2 the second filename to query, may be null + * @return true if the filenames are equal, null equals null + */ + public static boolean equals(String filename1, String filename2) { + if (filename1 == filename2) { + return true; + } + if (filename1 == null || filename2 == null) { + return false; + } + if (SYSTEM_SEPARATOR == WINDOWS_SEPARATOR) { + return filename1.equalsIgnoreCase(filename2); + } else { + return filename1.equals(filename2); + } + } + + /** + * Checks whether two filenames are equal after both have been normalized + * and using the case rules of the system. + * <p> + * Both filenames are first passed to [EMAIL PROTECTED] #normalize(String)}. + * The check is then performed case sensitive on Unix and case insensitive on Windows. + * + * @param filename1 the first filename to query, may be null + * @param filename2 the second filename to query, may be null + * @return true if the filenames are equal, null equals null + */ + public static boolean equalsNormalized(String filename1, String filename2) { + if (filename1 == filename2) { + return true; + } + if (filename1 == null || filename2 == null) { + return false; + } + filename1 = normalize(filename1); + filename2 = normalize(filename2); + if (SYSTEM_SEPARATOR == WINDOWS_SEPARATOR) { + return filename1.equalsIgnoreCase(filename2); + } else { + return filename1.equals(filename2); + } + } + + //----------------------------------------------------------------------- + /** + * Checks whether the extension of the filename is that specified + * using the case rules of the system. * <p> * This method obtains the extension as the textual part of the filename * after the last dot. There must be no directory separator after the dot. @@ -663,7 +759,8 @@ } /** - * Checks whether the extension of the filename is one of those specified. + * Checks whether the extension of the filename is one of those specified + * using the case rules of the system. * <p> * This method obtains the extension as the textual part of the filename * after the last dot. There must be no directory separator after the dot. @@ -698,7 +795,8 @@ } /** - * Checks whether the extension of the filename is one of those specified. + * Checks whether the extension of the filename is one of those specified + * using the case rules of the system. * <p> * This method obtains the extension as the textual part of the filename * after the last dot. There must be no directory separator after the dot. @@ -721,15 +819,25 @@ //----------------------------------------------------------------------- /** - * See if a particular piece of text, often a filename, - * matches to a specified wildcard, as seen on DOS/UNIX command lines. + * Checks a filename to see if it matches the specified wildcard matcher. + * <p> + * The wildcard matcher uses the characters '?' and '*' to represent a + * single or multiple wildcard characters. + * This is the same as often found on Dos/Unix command lines. + * <pre> + * wildcardMatch("c.txt", "*.txt") --> true + * wildcardMatch("c.txt", "*.jpg") --> false + * wildcardMatch("a/b/c.txt", "a/b/*") --> true + * wildcardMatch("c.txt", "*.???") --> true + * wildcardMatch("c.txt", "*.????") --> false + * </pre> * * @param filename the filename to match on - * @param wildcard the wildcard string to match against + * @param wildcardMatcher the wildcard string to match against * @return true if the filename matches the wilcard string */ - public static boolean wildcardMatch(String filename, String wildcard) { - String[] wcs = splitOnTokens(wildcard); + public static boolean wildcardMatch(String filename, String wildcardMatcher) { + String[] wcs = splitOnTokens(wildcardMatcher); int textIdx = 0; int wcsIdx = 0;
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]