对于那些寻求一般解决方案的人,这些可能是常见的标准:
- 文件名应类似于字符串。
- 编码应尽可能是可逆的。
- 碰撞的可能性应最小化。
为此,我们可以使用正则表达式来匹配非法字符,对它们进行百分比编码,然后限制编码字符串的长度。
private static final Pattern PATTERN = Pattern.compile("[^A-Za-z0-9_\\-]");
private static final int MAX_LENGTH = 127;
public static String escapeStringAsFilename(String in){
StringBuffer sb = new StringBuffer();
// Apply the regex.
Matcher m = PATTERN.matcher(in);
while (m.find()) {
// Convert matched character to percent-encoded.
String replacement = "%"+Integer.toHexString(m.group().charAt(0)).toUpperCase();
m.appendReplacement(sb,replacement);
}
m.appendTail(sb);
String encoded = sb.toString();
// Truncate the string.
int end = Math.min(encoded.length(),MAX_LENGTH);
return encoded.substring(0,end);
}
模式
上面的模式基于POSIX规范中允许的字符的保守子集。
如果要允许点字符,请使用:
private static final Pattern PATTERN = Pattern.compile("[^A-Za-z0-9_\\-\\.]");
只是要警惕诸如“”这样的字符串。和“ ..”
如果要避免在不区分大小写的文件系统上发生冲突,则需要转义大写字母:
private static final Pattern PATTERN = Pattern.compile("[^a-z0-9_\\-]");
或转义小写字母:
private static final Pattern PATTERN = Pattern.compile("[^A-Z0-9_\\-]");
您可以选择将特定文件系统的保留字符列入黑名单,而不是使用白名单。EG此正则表达式适合FAT32文件系统:
private static final Pattern PATTERN = Pattern.compile("[%\\.\"\\*/:<>\\?\\\\\\|\\+,\\.;=\\[\\]]");
长度
在Android上,安全限制为127个字符。许多文件系统允许255个字符。
如果您希望保留弦的尾部而不是头部,请使用:
// Truncate the string.
int start = Math.max(0,encoded.length()-MAX_LENGTH);
return encoded.substring(start,encoded.length());
解码
要将文件名转换回原始字符串,请使用:
URLDecoder.decode(filename, "UTF-8");
局限性
由于较长的字符串会被截断,因此在编码时可能会发生名称冲突,在解码时可能会损坏名称。