Skip to content

Commit 96463c0

Browse files
author
Gary Gregory
committed
Add FileSystem.normalizeSeparators().
Close Javadoc tags.
1 parent cdef9c2 commit 96463c0

3 files changed

Lines changed: 78 additions & 20 deletions

File tree

src/changes/changes.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,9 @@ The <action> type attribute can be add,update,fix,remove.
141141
<action dev="ggregory" type="add" due-to="Gary Gregory">
142142
Add FileSystem.getNameSeparator().
143143
</action>
144+
<action dev="ggregory" type="add" due-to="Gary Gregory">
145+
Add FileSystem.normalizeSeparators().
146+
</action>
144147
<!-- UPDATE -->
145148
<action dev="ggregory" type="update" due-to="Dependabot">
146149
Bump Maven Javadoc plugin from 3.2.0 to 3.3.0.

src/main/java/org/apache/commons/io/FileSystem.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,18 @@ private static boolean isOsNameMatch(final String osName, final String osNamePre
210210
return osName.toUpperCase(Locale.ROOT).startsWith(osNamePrefix.toUpperCase(Locale.ROOT));
211211
}
212212

213+
/**
214+
* Null-safe replace.
215+
*
216+
* @param path the path to be changed, null ignored.
217+
* @param oldChar the old character.
218+
* @param newChar the new character.
219+
* @return the new path.
220+
*/
221+
private static String replace(final String path, final char oldChar, final char newChar) {
222+
return path == null ? null : path.replace(oldChar, newChar);
223+
}
224+
213225
private final boolean casePreserving;
214226
private final boolean caseSensitive;
215227
private final char[] illegalFileNameChars;
@@ -218,6 +230,7 @@ private static boolean isOsNameMatch(final String osName, final String osNamePre
218230
private final String[] reservedFileNames;
219231
private final boolean supportsDriveLetter;
220232
private final char nameSeparator;
233+
221234
private final char nameSeparatorOther;
222235

223236
/**
@@ -356,6 +369,17 @@ public boolean isReservedFileName(final CharSequence candidate) {
356369
return Arrays.binarySearch(reservedFileNames, candidate) >= 0;
357370
}
358371

372+
/**
373+
* Converts all separators to the Windows separator of backslash.
374+
*
375+
* @param path the path to be changed, null ignored
376+
* @return the updated path
377+
* @since 2.12.0
378+
*/
379+
public String normalizeSeparators(final String path) {
380+
return replace(path, nameSeparatorOther, nameSeparator);
381+
}
382+
359383
/**
360384
* Tests whether this file system support driver letters.
361385
* <p>

src/main/java/org/apache/commons/io/FilenameUtils.java

Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,24 @@
3232
* When dealing with file names you can hit problems when moving from a Windows
3333
* based development machine to a Unix based production machine.
3434
* This class aims to help avoid those problems.
35+
* </p>
3536
* <p>
3637
* <b>NOTE</b>: You may be able to avoid using this class entirely simply by
3738
* using JDK {@link java.io.File File} objects and the two argument constructor
3839
* {@link java.io.File#File(java.io.File, java.lang.String) File(File,String)}.
40+
* </p>
3941
* <p>
4042
* Most methods on this class are designed to work the same on both Unix and Windows.
4143
* Those that don't include 'System', 'Unix' or 'Windows' in their name.
44+
* </p>
4245
* <p>
4346
* Most methods recognize both separators (forward and back), and both
4447
* sets of prefixes. See the Javadoc of each method for details.
48+
* </p>
4549
* <p>
4650
* This class defines six components within a file name
4751
* (example C:\dev\project\file.txt):
52+
* </p>
4853
* <ul>
4954
* <li>the prefix - C:\</li>
5055
* <li>the path - dev\project\</li>
@@ -53,13 +58,16 @@
5358
* <li>the base name - file</li>
5459
* <li>the extension - txt</li>
5560
* </ul>
61+
* <p>
5662
* Note that this class works best if directory file names end with a separator.
5763
* If you omit the last separator, it is impossible to determine if the file name
5864
* corresponds to a file or a directory. As a result, we have chosen to say
5965
* it corresponds to a file.
66+
* </p>
6067
* <p>
6168
* This class only supports Unix and Windows style names.
6269
* Prefixes are matched as follows:
70+
* </p>
6371
* <pre>
6472
* Windows:
6573
* a\b\c.txt --&gt; "" --&gt; relative
@@ -76,10 +84,13 @@
7684
* ~user/a/b/c.txt --&gt; "~user/" --&gt; named user
7785
* ~user --&gt; "~user/" --&gt; named user (slash added)
7886
* </pre>
87+
* <p>
7988
* Both prefix styles are matched always, irrespective of the machine that you are
8089
* currently running on.
90+
* </p>
8191
* <p>
8292
* Origin of code: Excalibur, Alexandria, Tomcat, Commons-Utils.
93+
* </p>
8394
*
8495
* @since 1.1
8596
*/
@@ -326,7 +337,7 @@ private static String doNormalize(final String fileName, final char separator, f
326337
fileName.getChars(0, fileName.length(), array, 0);
327338

328339
// fix separators throughout
329-
final char otherSeparator = separator == SYSTEM_NAME_SEPARATOR ? OTHER_SEPARATOR : SYSTEM_NAME_SEPARATOR;
340+
final char otherSeparator = flipSeparator(separator);
330341
for (int i = 0; i < array.length; i++) {
331342
if (array[i] == otherSeparator) {
332343
array[i] = separator;
@@ -409,6 +420,7 @@ private static String doNormalize(final String fileName, final char separator, f
409420
* <p>
410421
* No processing is performed on the fileNames other than comparison,
411422
* thus this is merely a null-safe case-sensitive equals.
423+
* </p>
412424
*
413425
* @param fileName1 the first fileName to query, may be null
414426
* @param fileName2 the second fileName to query, may be null
@@ -456,6 +468,7 @@ public static boolean equals(String fileName1, String fileName2, final boolean n
456468
* <p>
457469
* Both fileNames are first passed to {@link #normalize(String)}.
458470
* The check is then performed in a case-sensitive manner.
471+
* </p>
459472
*
460473
* @param fileName1 the first fileName to query, may be null
461474
* @param fileName2 the second fileName to query, may be null
@@ -473,6 +486,7 @@ public static boolean equalsNormalized(final String fileName1, final String file
473486
* Both fileNames are first passed to {@link #normalize(String)}.
474487
* The check is then performed case-sensitive on Unix and
475488
* case-insensitive on Windows.
489+
* </p>
476490
*
477491
* @param fileName1 the first fileName to query, may be null
478492
* @param fileName2 the second fileName to query, may be null
@@ -488,6 +502,7 @@ public static boolean equalsNormalizedOnSystem(final String fileName1, final Str
488502
* <p>
489503
* No processing is performed on the fileNames other than comparison.
490504
* The check is case-sensitive on Unix and case-insensitive on Windows.
505+
* </p>
491506
*
492507
* @param fileName1 the first fileName to query, may be null
493508
* @param fileName2 the second fileName to query, may be null
@@ -525,6 +540,7 @@ private static int getAdsCriticalOffset(final String fileName) {
525540
* <p>
526541
* This method will handle a file in either Unix or Windows format.
527542
* The text after the last forward or backslash and before the last dot is returned.
543+
* </p>
528544
* <pre>
529545
* a/b/c.txt --&gt; c
530546
* a.txt --&gt; a
@@ -533,6 +549,7 @@ private static int getAdsCriticalOffset(final String fileName) {
533549
* </pre>
534550
* <p>
535551
* The output will be the same irrespective of the machine that the code is running on.
552+
* </p>
536553
*
537554
* @param fileName the fileName to query, null returns null
538555
* @return the name of the file without the path, or an empty string if none exists. Null bytes inside string
@@ -547,6 +564,7 @@ public static String getBaseName(final String fileName) {
547564
* <p>
548565
* This method returns the textual part of the fileName after the last dot.
549566
* There must be no directory separator after the dot.
567+
* </p>
550568
* <pre>
551569
* foo.txt --&gt; "txt"
552570
* a/b/c.jpg --&gt; "jpg"
@@ -563,6 +581,7 @@ public static String getBaseName(final String fileName) {
563581
* alternate data stream (bar.txt) on the file foo.exe. The method used to return
564582
* ".txt" here, which would be misleading. Commons IO 2.7, and later versions, are throwing
565583
* an {@link IllegalArgumentException} for names like this.
584+
* </p>
566585
*
567586
* @param fileName the fileName to retrieve the extension of.
568587
* @return the extension of the file or an empty string if none exists or {@code null}
@@ -587,6 +606,7 @@ public static String getExtension(final String fileName) throws IllegalArgumentE
587606
* This method will handle a file in either Unix or Windows format.
588607
* The method is entirely text based, and returns the text before and
589608
* including the last forward or backslash.
609+
* </p>
590610
* <pre>
591611
* C:\a\b\c.txt --&gt; C:\a\b\
592612
* ~/a/b/c.txt --&gt; ~/a/b/
@@ -602,6 +622,7 @@ public static String getExtension(final String fileName) throws IllegalArgumentE
602622
* </pre>
603623
* <p>
604624
* The output will be the same irrespective of the machine that the code is running on.
625+
* </p>
605626
*
606627
* @param fileName the fileName to query, null returns null
607628
* @return the path of the file, an empty string if none exists, null if invalid
@@ -617,6 +638,7 @@ public static String getFullPath(final String fileName) {
617638
* This method will handle a file in either Unix or Windows format.
618639
* The method is entirely text based, and returns the text before the
619640
* last forward or backslash.
641+
* </p>
620642
* <pre>
621643
* C:\a\b\c.txt --&gt; C:\a\b
622644
* ~/a/b/c.txt --&gt; ~/a/b
@@ -632,6 +654,7 @@ public static String getFullPath(final String fileName) {
632654
* </pre>
633655
* <p>
634656
* The output will be the same irrespective of the machine that the code is running on.
657+
* </p>
635658
*
636659
* @param fileName the fileName to query, null returns null
637660
* @return the path of the file, an empty string if none exists, null if invalid
@@ -645,6 +668,7 @@ public static String getFullPathNoEndSeparator(final String fileName) {
645668
* <p>
646669
* This method will handle a file in either Unix or Windows format.
647670
* The text after the last forward or backslash is returned.
671+
* </p>
648672
* <pre>
649673
* a/b/c.txt --&gt; c.txt
650674
* a.txt --&gt; a.txt
@@ -653,6 +677,7 @@ public static String getFullPathNoEndSeparator(final String fileName) {
653677
* </pre>
654678
* <p>
655679
* The output will be the same irrespective of the machine that the code is running on.
680+
* </p>
656681
*
657682
* @param fileName the fileName to query, null returns null
658683
* @return the name of the file without the path, or an empty string if none exists.
@@ -671,6 +696,7 @@ public static String getName(final String fileName) {
671696
* This method will handle a file in either Unix or Windows format.
672697
* The method is entirely text based, and returns the text before and
673698
* including the last forward or backslash.
699+
* </p>
674700
* <pre>
675701
* C:\a\b\c.txt --&gt; a\b\
676702
* ~/a/b/c.txt --&gt; a/b/
@@ -680,9 +706,11 @@ public static String getName(final String fileName) {
680706
* </pre>
681707
* <p>
682708
* The output will be the same irrespective of the machine that the code is running on.
709+
* </p>
683710
* <p>
684711
* This method drops the prefix from the result.
685712
* See {@link #getFullPath(String)} for the method that retains the prefix.
713+
* </p>
686714
*
687715
* @param fileName the fileName to query, null returns null
688716
* @return the path of the file, an empty string if none exists, null if invalid.
@@ -699,6 +727,7 @@ public static String getPath(final String fileName) {
699727
* This method will handle a file in either Unix or Windows format.
700728
* The method is entirely text based, and returns the text before the
701729
* last forward or backslash.
730+
* </p>
702731
* <pre>
703732
* C:\a\b\c.txt --&gt; a\b
704733
* ~/a/b/c.txt --&gt; a/b
@@ -708,9 +737,11 @@ public static String getPath(final String fileName) {
708737
* </pre>
709738
* <p>
710739
* The output will be the same irrespective of the machine that the code is running on.
740+
* </p>
711741
* <p>
712742
* This method drops the prefix from the result.
713743
* See {@link #getFullPathNoEndSeparator(String)} for the method that retains the prefix.
744+
* </p>
714745
*
715746
* @param fileName the fileName to query, null returns null
716747
* @return the path of the file, an empty string if none exists, null if invalid.
@@ -726,6 +757,7 @@ public static String getPathNoEndSeparator(final String fileName) {
726757
* <p>
727758
* This method will handle a file in either Unix or Windows format.
728759
* The prefix includes the first slash in the full fileName where applicable.
760+
* </p>
729761
* <pre>
730762
* Windows:
731763
* a\b\c.txt --&gt; "" --&gt; relative
@@ -745,6 +777,7 @@ public static String getPathNoEndSeparator(final String fileName) {
745777
* <p>
746778
* The output will be the same irrespective of the machine that the code is running on.
747779
* ie. both Unix and Windows prefixes are matched regardless.
780+
* </p>
748781
*
749782
* @param fileName the fileName to query, null returns null
750783
* @return the prefix of the file, null if invalid. Null bytes inside string will be removed
@@ -768,10 +801,12 @@ public static String getPrefix(final String fileName) {
768801
* Returns the length of the fileName prefix, such as {@code C:/} or {@code ~/}.
769802
* <p>
770803
* This method will handle a file in either Unix or Windows format.
804+
* </p>
771805
* <p>
772806
* The prefix length includes the first slash in the full fileName
773807
* if applicable. Thus, it is possible that the length returned is greater
774808
* than the length of the input string.
809+
* </p>
775810
* <pre>
776811
* Windows:
777812
* a\b\c.txt --&gt; 0 --&gt; relative
@@ -795,10 +830,12 @@ public static String getPrefix(final String fileName) {
795830
* <p>
796831
* The output will be the same irrespective of the machine that the code is running on.
797832
* ie. both Unix and Windows prefixes are matched regardless.
798-
*
833+
* </p>
834+
* <p>
799835
* Note that a leading // (or \\) is used to indicate a UNC name on Windows.
800836
* These must be followed by a server name, so double-slashes are not collapsed
801837
* to a single slash at the start of the fileName.
838+
* </p>
802839
*
803840
* @param fileName the fileName to find the prefix in, null returns -1
804841
* @return the length of the prefix, -1 if invalid or null
@@ -1410,43 +1447,35 @@ private static String requireNonNullChars(final String path) {
14101447
}
14111448
return path;
14121449
}
1450+
14131451
/**
14141452
* Converts all separators to the system separator.
14151453
*
1416-
* @param path the path to be changed, null ignored
1417-
* @return the updated path
1454+
* @param path the path to be changed, null ignored.
1455+
* @return the updated path.
14181456
*/
14191457
public static String separatorsToSystem(final String path) {
1420-
if (path == null) {
1421-
return null;
1422-
}
1423-
return isSystemWindows() ? separatorsToWindows(path) : separatorsToUnix(path);
1458+
return FileSystem.getCurrent().normalizeSeparators(path);
14241459
}
14251460

14261461
/**
14271462
* Converts all separators to the Unix separator of forward slash.
14281463
*
1429-
* @param path the path to be changed, null ignored
1430-
* @return the updated path
1464+
* @param path the path to be changed, null ignored.
1465+
* @return the new path.
14311466
*/
14321467
public static String separatorsToUnix(final String path) {
1433-
if (path == null || path.indexOf(WINDOWS_NAME_SEPARATOR) == NOT_FOUND) {
1434-
return path;
1435-
}
1436-
return path.replace(WINDOWS_NAME_SEPARATOR, UNIX_NAME_SEPARATOR);
1468+
return FileSystem.LINUX.normalizeSeparators(path);
14371469
}
14381470

14391471
/**
14401472
* Converts all separators to the Windows separator of backslash.
14411473
*
1442-
* @param path the path to be changed, null ignored
1443-
* @return the updated path
1474+
* @param path the path to be changed, null ignored.
1475+
* @return the updated path.
14441476
*/
14451477
public static String separatorsToWindows(final String path) {
1446-
if (path == null || path.indexOf(UNIX_NAME_SEPARATOR) == NOT_FOUND) {
1447-
return path;
1448-
}
1449-
return path.replace(UNIX_NAME_SEPARATOR, WINDOWS_NAME_SEPARATOR);
1478+
return FileSystem.WINDOWS.normalizeSeparators(path);
14501479
}
14511480

14521481
/**
@@ -1491,6 +1520,7 @@ static String[] splitOnTokens(final String text) {
14911520

14921521
return list.toArray(EMPTY_STRING_ARRAY);
14931522
}
1523+
14941524
/**
14951525
* Returns '/' if given true, '\\' otherwise.
14961526
*
@@ -1500,6 +1530,7 @@ static String[] splitOnTokens(final String text) {
15001530
private static char toSeparator(final boolean unixSeparator) {
15011531
return unixSeparator ? UNIX_NAME_SEPARATOR : WINDOWS_NAME_SEPARATOR;
15021532
}
1533+
15031534
/**
15041535
* Checks a fileName to see if it matches the specified wildcard matcher,
15051536
* always testing case-sensitive.

0 commit comments

Comments
 (0)