Validar un nombre de archivo en Windows

public static boolean isValidName(String text) { Pattern pattern = Pattern.compile("^[^/./\\:*?\"|]+$"); Matcher matcher = pattern.matcher(text); boolean isMatch = matcher.matches(); return isMatch; } 

¿Este método garantiza un nombre de archivo válido en Windows?

Teniendo en cuenta los requisitos especificados en la documentación de MSDN anteriormente citada , la siguiente expresión regular debería hacer un buen trabajo:

 public static boolean isValidName(String text) { Pattern pattern = Pattern.compile( "# Match a valid Windows filename (unspecified file system). \n" + "^ # Anchor to start of string. \n" + "(?! # Assert filename is not: CON, PRN, \n" + " (?: # AUX, NUL, COM1, COM2, COM3, COM4, \n" + " CON|PRN|AUX|NUL| # COM5, COM6, COM7, COM8, COM9, \n" + " COM[1-9]|LPT[1-9] # LPT1, LPT2, LPT3, LPT4, LPT5, \n" + " ) # LPT6, LPT7, LPT8, and LPT9... \n" + " (?:\\.[^.]*)? # followed by optional extension \n" + " $ # and end of string \n" + ") # End negative lookahead assertion. \n" + "[^<>:\"/\\\\|?*\\x00-\\x1F]* # Zero or more valid filename chars.\n" + "[^<>:\"/\\\\|?*\\x00-\\x1F\\ .] # Last char is not a space or dot. \n" + "$ # Anchor to end of string. ", Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE | Pattern.COMMENTS); Matcher matcher = pattern.matcher(text); boolean isMatch = matcher.matches(); return isMatch; } 

Tenga en cuenta que esta expresión regular no impone ningún límite en la longitud del nombre de archivo, pero un nombre de archivo real puede estar limitado a 260 o 32767 caracteres según la plataforma.

No es suficiente, en Windows y DOS, algunas palabras también pueden estar reservadas y no pueden usarse como nombres de archivo.

 CON, PRN, AUX, CLOCK$, NUL COM0, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9 LPT0, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9. 

Ver ~

http://en.wikipedia.org/wiki/Filename


Editar:

Windows generalmente limita los nombres de archivo a 260 caracteres. Pero el nombre del archivo en realidad debe ser más corto que eso, ya que la ruta completa (como C: \ Program Files \ filename.txt) se incluye en este recuento de caracteres.

Es por esto que ocasionalmente puede encontrar un error al copiar un archivo con un nombre de archivo muy largo a una ubicación que tiene una ruta más larga que su ubicación actual.

Bueno, creo que el siguiente método garantizaría un nombre de archivo válido:

 public static boolean isValidName(String text) { try { File file = new File(text); file.createNewFile(); if(file.exists()) file.delete(); return true; } catch(Exception ex){} return false; } 

¿Qué piensas?

Un método que garantice, en general, que un nombre de archivo de Windows es válido, que sería legal crear un archivo de ese nombre, sería imposible de implementar.

Es relativamente sencillo garantizar que un nombre de archivo de Windows no sea válido . Algunas de las otras expresiones regulares intentan hacer esto. Sin embargo, la pregunta original solicita una afirmación más sólida: un método que garantiza que el nombre de archivo sea válido en Windows.

La referencia de MSDN citada en otras respuestas indica que un nombre de archivo de Windows no puede contener “Cualquier otro carácter que el sistema de archivos de destino no permita”. Por ejemplo, un archivo que contenga NUL no sería válido en algunos sistemas de archivos, al igual que los caracteres Unicode extendidos en algunos sistemas de archivos anteriores. Por lo tanto, un archivo llamado ☃.txt sería válido en algunos casos, pero no en otros. Entonces, si un hipotético isValidName(\"☃\") devolvería true depende del sistema de archivos subyacente.

Supongamos, sin embargo, que dicha función es conservadora y requiere que el nombre del archivo esté formado por caracteres ASCII imprimibles. Todas las versiones modernas de Windows admiten nativamente los formatos de archivo NTFS, FAT32 y FAT16, que aceptan nombres de archivo Unicode. Pero se pueden instalar controladores para sistemas de archivos arbitrarios, y uno es libre de crear un sistema de archivos que no permita, por ejemplo, la letra ‘n’. Por lo tanto, ni siquiera un archivo simple como “snowman.txt” puede ser “garantizado” como válido.

Pero incluso con casos extremos a un lado, hay otras complicaciones. Por ejemplo, un archivo llamado “$ LogFile” no puede existir en la raíz de un volumen NTFS, pero puede existir en cualquier otro lugar del volumen. Por lo tanto, sin conocer el directorio, no podemos saber si “$ LogFile” es un nombre válido. Pero incluso “C: \ data \ $ LogFile” podría no ser válido si, por ejemplo, “c: \ data \” es un enlace simbólico a otra raíz de volumen NTFS. (De forma similar, “D: \ $ LogFile” puede ser válido si D: es un alias de un subdirectorio de un volumen NTFS).

Hay incluso más complicaciones. Las secuencias de datos alternativas en los archivos, por ejemplo, son legales en los volúmenes NTFS, por lo que “snowman.txt: ☃” puede ser válido. Los tres principales sistemas de archivos de Windows tienen restrucciones de longitud de ruta, por lo que la validez del nombre de archivo también es función de la ruta. Pero la longitud de la ruta física puede que ni siquiera esté disponible para isValidName si la ruta es un alias virtual, una unidad de red mapeada o un enlace simbólico en lugar de una ruta física en el volumen.

Algunos otros han sugerido una alternativa: crear un archivo por el nombre propuesto y luego eliminarlo, devolviendo verdadero si y solo si la creación tiene éxito. Este enfoque tiene varios problemas prácticos y teóricos. Uno, como se indicó anteriormente, es que la validez es una función tanto del nombre del archivo como de la ruta, por lo que la validez de c: \ test \ ☃.txt puede diferir de la validez de c: \ test2 \ ☃.txt. Además, la función no podría escribir el archivo por una serie de razones no relacionadas con la validez del archivo, como no tener permiso de escritura en el directorio. Una tercera falla es que no se requiere que la validez de un nombre de archivo sea no determinista: un sistema de archivos hipotético podría, por ejemplo, no permitir que un archivo eliminado sea reemplazado, o (en teoría) incluso podría decidir al azar si un nombre de archivo es válido.

Como alternativa, es bastante sencillo crear un método isInvalidFileName(String text) que devuelve verdadero si se garantiza que el archivo no será válido en Windows; nombres de archivo como “aux”, “*” y “abc.txt”. volvería verdadero. La operación de creación de archivos verificará primero que el nombre del archivo esté garantizado como inválido y, si devuelve falso, se detendrá. De lo contrario, el método podría intentar crear el archivo, mientras se prepara para el caso límite donde no se puede crear el archivo porque el nombre del archivo no es válido.

Publicar una nueva respuesta porque no tengo el umbral de reputación para comentar el código de Eng.Fouad

 public static boolean isValidName(String text) { try { File file = new File(text); if(file.createNewFile()) file.delete(); return true; } catch(Exception ex){} return false; } 

Un pequeño cambio en su respuesta que evita borrar un archivo preexistente. Los archivos solo se eliminan si se crearon durante esta llamada a método, mientras que el valor de retorno es el mismo.

Aquí puede encontrar los nombres de archivo permitidos.

Los siguientes caracteres no están permitidos:

  • < (menos que)
  • (mas grande que)

  • : (colon)
  • “(comillas dobles)
  • / (barra inclinada)
  • \ (barra invertida)
  • | (barra vertical o tubería)
  • ? (signo de interrogación)
  • * (asterisco)

  • Valor entero cero, a veces denominado carácter ASCII NUL.

  • Caracteres cuyas representaciones enteras están en el rango de 1 a 31, a excepción de las secuencias de datos alternativas donde se permiten estos caracteres. Para obtener más información sobre flujos de archivos, vea Flujos de archivos.
  • Cualquier otro carácter que el sistema de archivos de destino no permita.

Esta solución solo verificará si un nombre de archivo determinado es válido de acuerdo con las reglas del sistema operativo sin crear un archivo.

Todavía necesita manejar otras fallas cuando crea el archivo (por ejemplo, permisos insuficientes, falta de espacio en disco, restricciones de seguridad).

 import java.io.File; import java.io.IOException; public class FileUtils { public static boolean isFilenameValid(String file) { File f = new File(file); try { f.getCanonicalPath(); return true; } catch (IOException e) { return false; } } public static void main(String args[]) throws Exception { // true System.out.println(FileUtils.isFilenameValid("well.txt")); System.out.println(FileUtils.isFilenameValid("well well.txt")); System.out.println(FileUtils.isFilenameValid("")); //false System.out.println(FileUtils.isFilenameValid("test.T*T")); System.out.println(FileUtils.isFilenameValid("test|.TXT")); System.out.println(FileUtils.isFilenameValid("te?st.TXT")); System.out.println(FileUtils.isFilenameValid("con.TXT")); // windows System.out.println(FileUtils.isFilenameValid("prn.TXT")); // windows } } 

Se ve bien. Al menos si creemos en este recurso: http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx

Pero simplificaría el uso del código. Basta con buscar uno de estos caracteres para decir que el nombre no es válido, entonces:

 public static boolean isValidName(String text) { Pattern pattern = Pattern.compile("[^/./\\:*?\"<>|]"); return !pattern.matcher(text).find(); } 

Esta expresión regular es más simple y funcionará más rápido.

No estoy seguro de cómo implementarlo en Java (ya sea Regex o método propio). Pero, el sistema operativo Windows tiene las siguientes reglas para crear un archivo / directorio en el sistema de archivos:

  1. El nombre no es solo Dots
  2. Los nombres de dispositivos de Windows como AUX, CON, NUL, PRN, COM1, COM2, COM3, COM4, ​​COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9, no pueden ser utilizado para un nombre de archivo ni para el primer segmento de un nombre de archivo (es decir, test1 en test1.txt).
  3. Los nombres de los dispositivos no distinguen mayúsculas de minúsculas. (es decir, prn, PRN, Prn, etc. son idénticos).
  4. Todos los caracteres superiores a ASCII 31 que se utilizarán excepto “* /: <>? \ |

Entonces, el progtwig necesita seguir con estas reglas. Espero que cubra las reglas de validación de tu pregunta.

Puede verificar todos los nombres reservados (AUX, CON y similares) y luego usar este código:

 bool invalidName = GetFileAttributes(name) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_INVALID_NAME; 

para verificar cualquier restricción adicional. Pero tenga en cuenta que si busca un nombre en un directorio no existente obtendrá ERROR_PATH_NOT_FOUND si el nombre es realmente válido o no.

De todos modos, debes recordar el viejo dicho:

Es más fácil pedir perdón que obtener permiso.

¿Qué tal si permites que la clase File haga tu validación?

 public static boolean isValidName(String text) { try { File file = new File(text); return file.getPath().equals(text); } catch(Exception ex){} return false; }