setborder - Java: ¿cómo saber si un nombre de archivo es válido?
setborder java (8)
Así es como lo implementé:
public boolean isValidFileName(final String aFileName) {
final File aFile = new File(aFileName);
boolean isValid = true;
try {
if (aFile.createNewFile()) {
aFile.delete();
}
} catch (IOException e) {
isValid = false;
}
return isValid;
}
Esta pregunta ya tiene una respuesta aquí:
En mi aplicación Java estoy cambiando el nombre de los archivos a un nombre de archivo provisto en un parámetro String. Hay un método
boolean OKtoRename(String oldName, String newName)
que básicamente verifica si el nuevo Nombre ya no está ocupado por otro archivo, ya que no quisiera enterrar los existentes.
Ahora se me ocurrió que tal vez newName String no denotará un nombre de archivo válido. Así que pensé en agregar esta verificación al método:
if (new File(newName).isFile()) {
return false;
}
Lo cual obviamente no es la forma correcta de hacerlo, ya que en la mayoría de los casos el archivo nuevo aún no existe y, por lo tanto, aunque es correcto para Renombrar, la función devuelve falso.
Me preguntaba, ¿hay algún método (sé que no hay para los objetos java.io.File) como canExist()
? ¿O tendré que recurrir a regex para asegurarme de que newFile String no contenga caracteres no válidos (por ejemplo,?, *, ", :)? Me pregunto si tal vez haya una función escondida en alguna parte del JDK que me diga si una cadena posiblemente podría denotar un nombre de archivo válido.
Para mí, parece ser un problema dependiente del sistema operativo. Es posible que simplemente desee comprobar si hay algún carácter no válido en el nombre del archivo. Windows hace esto cuando intenta cambiar el nombre del archivo, aparece un mensaje que dice que un archivo no puede contener ninguno de los siguientes caracteres: / /: *? <> | No estoy seguro si su pregunta es "¿hay una biblioteca haciendo el trabajo por mí?" en ese caso, no conozco ninguno.
Recopilé una lista de caracteres de nombre de archivo ilegal (considerando los sistemas UNIX, Mac OS X y Windows) basados en algunas investigaciones en línea hace un par de meses. Si el nuevo nombre de archivo contiene alguno de estos, existe el riesgo de que no sea válido en todas las plataformas.
private static final char[] ILLEGAL_CHARACTERS = { ''/'', ''/n'', ''/r'', ''/t'', ''/0'', ''/f'', ''`'', ''?'', ''*'', ''//', ''<'', ''>'', ''|'', ''/"'', '':'' };
EDITAR: Me gustaría hacer hincapié en que esta no es una solución completa : como señaló un comentarista, aunque pase esta prueba, su nombre de archivo podría ser una palabra clave específica de Windows como COM, PRN, etc. Sin embargo, si su archivo nombre contiene cualquiera de estos caracteres, sin duda causará problemas en un entorno multiplataforma.
Si desarrolla para Eclipse, consulte org.eclipse.core.internal.resources.OS
public abstract class OS {
private static final String INSTALLED_PLATFORM;
public static final char[] INVALID_RESOURCE_CHARACTERS;
private static final String[] INVALID_RESOURCE_BASENAMES;
private static final String[] INVALID_RESOURCE_FULLNAMES;
static {
//find out the OS being used
//setup the invalid names
INSTALLED_PLATFORM = Platform.getOS();
if (INSTALLED_PLATFORM.equals(Platform.OS_WIN32)) {
//valid names and characters taken from http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/naming_a_file.asp
INVALID_RESOURCE_CHARACTERS = new char[] {''//', ''/'', '':'', ''*'', ''?'', ''"'', ''<'', ''>'', ''|''};
INVALID_RESOURCE_BASENAMES = new String[] {"aux", "com1", "com2", "com3", "com4", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
"com5", "com6", "com7", "com8", "com9", "con", "lpt1", "lpt2", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
"lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9", "nul", "prn"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$
Arrays.sort(INVALID_RESOURCE_BASENAMES);
//CLOCK$ may be used if an extension is provided
INVALID_RESOURCE_FULLNAMES = new String[] {"clock$"}; //$NON-NLS-1$
} else {
//only front slash and null char are invalid on UNIXes
//taken from http://www.faqs.org/faqs/unix-faq/faq/part2/section-2.html
INVALID_RESOURCE_CHARACTERS = new char[] {''/'', ''/0'',};
INVALID_RESOURCE_BASENAMES = null;
INVALID_RESOURCE_FULLNAMES = null;
}
}
/**
* Returns true if the given name is a valid resource name on this operating system,
* and false otherwise.
*/
public static boolean isNameValid(String name) {
//. and .. have special meaning on all platforms
if (name.equals(".") || name.equals("..")) //$NON-NLS-1$ //$NON-NLS-2$
return false;
if (INSTALLED_PLATFORM.equals(Platform.OS_WIN32)) {
//empty names are not valid
final int length = name.length();
if (length == 0)
return false;
final char lastChar = name.charAt(length-1);
// filenames ending in dot are not valid
if (lastChar == ''.'')
return false;
// file names ending with whitespace are truncated (bug 118997)
if (Character.isWhitespace(lastChar))
return false;
int dot = name.indexOf(''.'');
//on windows, filename suffixes are not relevant to name validity
String basename = dot == -1 ? name : name.substring(0, dot);
if (Arrays.binarySearch(INVALID_RESOURCE_BASENAMES, basename.toLowerCase()) >= 0)
return false;
return Arrays.binarySearch(INVALID_RESOURCE_FULLNAMES, name.toLowerCase()) < 0;
}
return true;
}
}
Solo algo que encontré, en java 7 y posteriores, hay una clase llamada Paths
que tiene un método llamado get
que toma una o más String
y tiros
InvalidPathException
: si la cadena de ruta de acceso no se puede convertir a una ruta
Use createNewFile()
, que creará atómicamente el archivo solo si aún no existe.
Si se crea el archivo, el nombre es válido y no está arruinando un archivo existente. A continuación, puede abrir los archivos y copiar datos de manera eficiente de uno a otro con FileChannel.transferXXX
operaciones FileChannel.transferXXX
.
Una cosa importante a tener en cuenta es que, en general, el cheque y la creación deben ser atómicos. Si primero verifica si una operación es segura y luego realiza la operación como un paso separado, las condiciones pueden haber cambiado mientras tanto, haciendo que la operación no sea segura.
En esta publicación relacionada se encuentra disponible material de reflexión: "Mover / copiar operaciones en Java".
Actualizar:
Desde esta respuesta, se han introducido las API de NIO.2, que agregan más interacción con el sistema de archivos.
Supongamos que tiene un programa interactivo y desea validar después de cada pulsación de tecla si el archivo es potencialmente válido. Por ejemplo, es posible que desee habilitar un botón "Guardar" solo cuando la entrada sea válida en lugar de abrir un cuadro de diálogo de error luego de presionar "Guardar". Crear y asegurar la eliminación de muchos archivos innecesarios que mi sugerencia anterior requeriría parece un desastre.
Con NIO.2, no puede crear una instancia de Path
contenga caracteres que sean ilegales para el sistema de archivos. Una InvalidPathException
se InvalidPathException
tan pronto como intente crear la Path
.
Sin embargo, no hay una API para validar nombres ilegales compuestos de caracteres válidos, como "PRN" en Windows. Como solución alternativa, la experimentación demostró que el uso de un nombre de archivo ilegal generaría una excepción distintiva al intentar acceder a los atributos (utilizando Files.getLastModifiedTime()
, por ejemplo).
Si especifica un nombre legal para un archivo que existe, no obtiene ninguna excepción.
Si especifica un nombre legal para un archivo que no existe, genera NoSuchFileException
.
Si especifica un nombre ilegal, se FileSystemException
.
Sin embargo, esto parece muy complicado y podría no ser confiable en otros sistemas operativos.
Utilizando
String validName = URLEncoder.encode( fileName , "UTF-8");
File newFile = new File( validName );
El trabajo
Acabo de encontrar hoy. No estoy seguro de si funciona el 100% del tiempo, pero hasta ahora, he podido crear nombres de archivo válidos.
Here se sugiere una forma específica del sistema.
public static boolean isFilenameValid(String file) {
File f = new File(file);
try {
f.getCanonicalPath();
return true;
} catch (IOException e) {
return false;
}
}