一般的な解決策を探している人にとって、これらは一般的な基準かもしれません:
- ファイル名は文字列に似ている必要があります。
- エンコーディングは、可能な場合は可逆でなければなりません。
- 衝突の可能性を最小限に抑える必要があります。
これを実現するには、正規表現を使用して不正な文字を照合し、パーセントエンコードしてから、エンコードされた文字列の長さを制限します。
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");
制限事項
長い文字列は切り捨てられるため、エンコード時に名前が衝突したり、デコード時に破損したりする可能性があります。