[
https://issues.apache.org/jira/browse/IO-555?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16253989#comment-16253989
]
Gary Gregory edited comment on IO-555 at 11/15/17 7:19 PM:
-----------------------------------------------------------
[[email protected]],
Great feedback so thank you again.
- Let's get our YAGNI on and for now make {{isIllegalFileNameChar(char)}}
private to iron out the current use case: Use Strings from an external data
source that is out of my control to generate file names to save files in a
given directory. The directory is already set up, all I need a clean file names
to create files in that directory.
- I can see indeed that adding a {{isIllegalFileName(CharSequence)}} would be
useful but I do not need it now. Can we table that one for later?
- I added a sanity check in the ctor: the char[] must not be null.
- I added a check of the replacement character:
{code:java}
if (isIllegalFileNameChar(replacement)) {
throw new IllegalArgumentException(String.format("The replacement
character '%s' cannot be one of the %s illegal characters: %s", replacement,
name(),
Arrays.toString(illegalFileNameChars)));
}
{code}
- "It might be useful to allow illegal chars to be dropped.": I would add
another API (later) called {{toLegalFileName(String candidate, char
replacement, boolean removeIllegalChars)}}. Is that what you had in mind?
- I updated the Javadoc to mention file name truncation: "If the file name
exceeds {@link #getMaxFileNameLength()}, then the name is truncated to {@link
#getMaxFileNameLength()}."
- WRT to the scale of the lengths, it characters, the docs on
https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
mention "255 characters".
New version:
{code:java}
import java.util.Arrays;
import java.util.Objects;
import org.apache.commons.lang3.SystemUtils;
// TODO Apache Commons IO 2.7
public enum FileSystem {
UNSUPPORTED(Integer.MAX_VALUE, Integer.MAX_VALUE, new char[] {}),
LINUX(255, 4096, new char[] {
// KEEP THIS ARRAY SORTED!
// @formatter:off
// ASCII NULL
0,
'/'
// @formatter:on
}),
MAC_OSX(255, 1024, new char[] {
// KEEP THIS ARRAY SORTED!
// @formatter:off
// ASCII NULL
0,
'/',
':'
// @formatter:on
}),
WINDOWS(255, 32000, new char[] {
// KEEP THIS ARRAY SORTED!
// @formatter:off
// ASCII NULL
0,
// 1-31 may be allowed in file streams
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28,
29, 30, 31,
'"', '*', '/', ':', '<', '>', '?', '\\', '|'
// @formatter:on
});
public static FileSystem getCurrent() {
if (SystemUtils.IS_OS_LINUX) {
return LINUX;
}
if (SystemUtils.IS_OS_MAC_OSX) {
return FileSystem.MAC_OSX;
}
if (SystemUtils.IS_OS_WINDOWS) {
return FileSystem.WINDOWS;
}
return UNSUPPORTED;
}
private final int maxFileNameLength;
private final int maxPathLength;
private final char[] illegalFileNameChars;
private FileSystem(final int maxFileLength, final int maxPathLength, final
char[] illegalFileNameChars) {
this.maxFileNameLength = maxFileLength;
this.maxPathLength = maxPathLength;
this.illegalFileNameChars =
Objects.requireNonNull(illegalFileNameChars, "illegalFileNameChars");
}
public char[] getIllegalFileNameChars() {
return this.illegalFileNameChars.clone();
}
public int getMaxFileNameLength() {
return maxFileNameLength;
}
public int getMaxPathLength() {
return maxPathLength;
}
private boolean isIllegalFileNameChar(final char c) {
return Arrays.binarySearch(illegalFileNameChars, c) >= 0;
}
/**
* Converts a candidate file name (without a path) like {@code
"filename.ext"} or {@code "filename"} to a legal file name. Illegal characters
in
* the candidate name are replaced by the {@code replacement} character. If
the file name exceeds {@link #getMaxFileNameLength()}, then the name
* is truncated to {@link #getMaxFileNameLength()}.
*
* @param candidate
* a candidate file name (without a path) like {@code
"filename.ext"} or {@code "filename"}
* @param replacement
* Illegal characters in the candidate name are replaced by this
character
* @return a String without illegal characters
*/
public String toLegalFileName(final String candidate, final char
replacement) {
if (isIllegalFileNameChar(replacement)) {
throw new IllegalArgumentException(String.format("The replacement
character '%s' cannot be one of the %s illegal characters: %s", replacement,
name(),
Arrays.toString(illegalFileNameChars)));
}
final String truncated = candidate.length() > maxFileNameLength ?
candidate.substring(0, maxFileNameLength) : candidate;
boolean changed = false;
final char[] charArray = truncated.toCharArray();
for (int i = 0; i < charArray.length; i++) {
if (isIllegalFileNameChar(charArray[i])) {
charArray[i] = replacement;
changed = true;
}
}
return changed ? String.valueOf(charArray) : truncated;
}
}
{code}
was (Author: garydgregory):
[[email protected]],
Great feedback so thank you again.
- Let's get our YAGNI on and for now make {{isIllegalFileNameChar(char)}}
private to iron out the current use case: Use Strings from an external data
source that is out of my control to generate file names to save files in a
given directory. The directory is already set up, all I need a clean file names
to create files in that directory.
- I can see indeed that adding a {{isIllegalFileName(CharSequence)}} would be
useful but I do not need it now. Can we table that one for later?
- I added a sanity check in the ctor: the char[] must not be null.
- I added a check of the replacement character:
{code:java}
if (isIllegalFileNameChar(replacement)) {
throw new IllegalArgumentException(String.format("The replacement
character '%s' cannot be one of the illegal characters for this file system:
%s",
replacement, Arrays.toString(illegalFileNameChars)));
}
{code}
- "It might be useful to allow illegal chars to be dropped.": I would add
another API (later) called {{toLegalFileName(String candidate, char
replacement, boolean removeIllegalChars)}}. Is that what you had in mind?
- I updated the Javadoc to mention file name truncation: "If the file name
exceeds {@link #getMaxFileNameLength()}, then the name is truncated to {@link
#getMaxFileNameLength()}."
- WRT to the scale of the lengths, it characters, the docs on
https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
mention "255 characters".
New version:
{code:java}
import java.util.Arrays;
import java.util.Objects;
import org.apache.commons.lang3.SystemUtils;
// TODO Apache Commons IO 2.7
public enum FileSystem {
UNSUPPORTED(Integer.MAX_VALUE, Integer.MAX_VALUE, new char[] {}),
LINUX(255, 4096, new char[] {
// KEEP THIS ARRAY SORTED!
// @formatter:off
// ASCII NULL
0,
'/'
// @formatter:on
}),
MAC_OSX(255, 1024, new char[] {
// KEEP THIS ARRAY SORTED!
// @formatter:off
// ASCII NULL
0,
'/',
':'
// @formatter:on
}),
WINDOWS(255, 32000, new char[] {
// KEEP THIS ARRAY SORTED!
// @formatter:off
// ASCII NULL
0,
// 1-31 may be allowed in file streams
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28,
29, 30, 31,
'"', '*', '/', ':', '<', '>', '?', '\\', '|'
// @formatter:on
});
public static FileSystem getCurrent() {
if (SystemUtils.IS_OS_LINUX) {
return LINUX;
}
if (SystemUtils.IS_OS_MAC_OSX) {
return FileSystem.MAC_OSX;
}
if (SystemUtils.IS_OS_WINDOWS) {
return FileSystem.WINDOWS;
}
return UNSUPPORTED;
}
private final int maxFileNameLength;
private final int maxPathLength;
private final char[] illegalFileNameChars;
private FileSystem(final int maxFileLength, final int maxPathLength, final
char[] illegalFileNameChars) {
this.maxFileNameLength = maxFileLength;
this.maxPathLength = maxPathLength;
this.illegalFileNameChars =
Objects.requireNonNull(illegalFileNameChars, "illegalFileNameChars");
}
public char[] getIllegalFileNameChars() {
return this.illegalFileNameChars.clone();
}
public int getMaxFileNameLength() {
return maxFileNameLength;
}
public int getMaxPathLength() {
return maxPathLength;
}
private boolean isIllegalFileNameChar(final char c) {
return Arrays.binarySearch(illegalFileNameChars, c) >= 0;
}
/**
* Converts a candidate file name (without a path) like {@code
"filename.ext"} or {@code "filename"} to a legal file name. Illegal characters
in
* the candidate name are replaced by the {@code replacement} character. If
the file name exceeds {@link #getMaxFileNameLength()}, then the name
* is truncated to {@link #getMaxFileNameLength()}.
*
* @param candidate
* a candidate file name (without a path) like {@code
"filename.ext"} or {@code "filename"}
* @param replacement
* Illegal characters in the candidate name are replaced by this
character
* @return a String without illegal characters
*/
public String toLegalFileName(final String candidate, final char
replacement) {
if (isIllegalFileNameChar(replacement)) {
throw new IllegalArgumentException(String.format("The replacement
character '%s' cannot be one of the %s illegal characters: %s", replacement,
name(),
Arrays.toString(illegalFileNameChars)));
}
final String truncated = candidate.length() > maxFileNameLength ?
candidate.substring(0, maxFileNameLength) : candidate;
boolean changed = false;
final char[] charArray = truncated.toCharArray();
for (int i = 0; i < charArray.length; i++) {
if (isIllegalFileNameChar(charArray[i])) {
charArray[i] = replacement;
changed = true;
}
}
return changed ? String.valueOf(charArray) : truncated;
}
}
{code}
> Add org.apache.commons.io.FilenameUtils.isIllegalWindowsFileName(char)
> ----------------------------------------------------------------------
>
> Key: IO-555
> URL: https://issues.apache.org/jira/browse/IO-555
> Project: Commons IO
> Issue Type: Improvement
> Reporter: Gary Gregory
> Assignee: Gary Gregory
> Fix For: 2.7
>
>
> Add {{org.apache.commons.io.FilenameUtils.isIllegalWindowsFileName(char)}}.
> {code:java}
> /**
> * Checks whether the given character is illegal in a Windows file names.
> * <p>
> * The illegal character are:
> * </p>
> * <ul>
> * <li>< (less than</li>
> * <li>> (greater than</li>
> * <li>: (colon</li>
> * <li>" (double quote</li>
> * <li>/ (forward slash</li>
> * <li>\ (backslash</li>
> * <li>| (vertical bar or pipe</li>
> * <li>? (question mark</li>
> * <li>* (asterisk</li>
> * <li>ASCII NUL (0)</li>
> * <li>Integer characters 1 through 31</li>
> * <li>There may be other characters that the file name does not allow.
> Please see
> * <a
> href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx">Naming
> Files, Paths,
> * and Namespaces</a></li>
> * </ul>
> *
> * @see <a
> href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx">Naming
> Files,
> * Paths, and Namespaces</a>
> * @param c
> * the character to check
> * @return whether the give character is legal
> * @since 2.7
> */
> {code}
> I use this method as a building block to create file names based on Strings
> from other sources.
> A further contribution could be: {{String toLegalWindowsFileName(String
> input, char replacementChar)}}
--
This message was sent by Atlassian JIRA
(v6.4.14#64029)