Para aquellos que buscan una solución general, estos pueden ser criterios comunes:
- El nombre del archivo debe parecerse a la cadena.
- La codificación debe ser reversible siempre que sea posible.
- Debe minimizarse la probabilidad de colisiones.
Para lograr esto, podemos usar expresiones regulares para hacer coincidir caracteres ilegales, codificarlos en porcentaje y luego restringir la longitud de la cadena codificada.
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);
}
Patrones
El patrón anterior se basa en un subconjunto conservador de caracteres permitidos en la especificación POSIX .
Si desea permitir el carácter de punto, use:
private static final Pattern PATTERN = Pattern.compile("[^A-Za-z0-9_\\-\\.]");
Solo tenga cuidado con cadenas como "." y ".."
Si desea evitar colisiones en sistemas de archivos que no distinguen entre mayúsculas y minúsculas, deberá escapar de las mayúsculas:
private static final Pattern PATTERN = Pattern.compile("[^a-z0-9_\\-]");
O escapar de las minúsculas:
private static final Pattern PATTERN = Pattern.compile("[^A-Z0-9_\\-]");
En lugar de utilizar una lista blanca, puede optar por incluir en la lista negra los caracteres reservados para su sistema de archivos específico. Por ejemplo, esta expresión regular se adapta a los sistemas de archivos FAT32:
private static final Pattern PATTERN = Pattern.compile("[%\\.\"\\*/:<>\\?\\\\\\|\\+,\\.;=\\[\\]]");
Longitud
En Android, 127 caracteres es el límite seguro. Muchos sistemas de archivos permiten 255 caracteres.
Si prefiere retener la cola, en lugar de la cabeza de su cuerda, use:
// Truncate the string.
int start = Math.max(0,encoded.length()-MAX_LENGTH);
return encoded.substring(start,encoded.length());
Descodificación
Para convertir el nombre de archivo de nuevo a la cadena original, use:
URLDecoder.decode(filename, "UTF-8");
Limitaciones
Debido a que las cadenas más largas se truncan, existe la posibilidad de una colisión de nombres al codificar o de daños al decodificar.