Для тех, кто ищет общее решение, это могут быть общие критерии:
- Имя файла должно напоминать строку.
- По возможности кодирование должно быть обратимым.
- Вероятность столкновений должна быть минимизирована.
Для этого мы можем использовать регулярное выражение для сопоставления недопустимых символов, кодировать их в процентах , а затем ограничивать длину закодированной строки.
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");
Ограничения
Поскольку более длинные строки усекаются, существует вероятность конфликта имен при кодировании или повреждения при декодировании.