Java - ¿Cómo saber si un nombre de archivo es válido? [duplicar]


Esta pregunta ya tiene una respuesta aquí:

En mi aplicación Java estoy cambiando el nombre de los archivos a un nombre de archivo proporcionado en un parámetro de cadena. Hay un método

boolean OKtoRename(String oldName, String newName)

Que básicamente comprueba si el newName no está ya tomado por algún otro archivo, ya que no querría enterrar los existentes.

Ahora se me ocurrió que tal vez la cadena newName no denotará un nombre de archivo válido. Así que pensé en añadir esta comprobación al método:

if (new File(newName).isFile()) { 
    return false; 
}

Que obviamente no es la forma correcta de hacerlo, ya que en la mayoría de los casos el newFile aún no existe y por lo tanto, aunque es OKtoRename, la función devuelve false.

Me preguntaba, ¿hay un método (sé que no hay para los objetos java. io. File) como canExist()? O tendría que recurrir a expresiones regulares para asegurarme de que la cadena de newFile no contiene caracteres no válidos (p. ej. ?, *, ", :)? Me pregunto si quizás hay una función oculta en algún lugar del JDK que me diga si una cadena podría denotar un nombre de archivo válido.

 48
Author: OscarRyz, 2009-05-21

8 answers

Uso createNewFile(), que creará atomicamente el archivo solo si aún no existe.

Si se crea el archivo, el nombre es válido y no se trata de clobbering un archivo existente. A continuación, puede abrir los archivos y copiar datos de manera eficiente de uno a otro con FileChannel.transferXXX operaciones.

Una cosa importante a tener en cuenta que, en general, el cheque y la creación deben ser atómicos. Si primero comprueba si una operación es segura, entonces realice la operación por separado paso, las condiciones pueden haber cambiado en el ínterin, haciendo la operación insegura.

Otros elementos de reflexión están disponibles en este post relacionado: "Mover/Copiar operaciones en Java."


Actualización:

Desde esta respuesta, el NIO.Se han introducido 2 API, que añaden 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. Para por ejemplo, es posible que desee habilitar un botón "Guardar" solo cuando la entrada es válida en lugar de aparecer un cuadro de diálogo de error después de presionar "Guardar". Crear y asegurar la eliminación de una gran cantidad de archivos innecesarios que mi sugerencia anterior requeriría parece un desastre.

Con NIO.2, no puede crear una instancia Path que contenga caracteres que sean ilegales para el sistema de archivos. Se genera un InvalidPathException tan pronto como se intenta crear el 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 mostró que el uso de un nombre de archivo ilegal generaría una excepción distinta al intentar acceder a atributos (usando Files.getLastModifiedTime(), por ejemplo).

Si especifica un nombre legal para un archivo que existe, no obtiene ninguna excepción.

Si se especifica un nombre legal para un archivo que no existe, se genera NoSuchFileException.

Si se especifica un nombre ilegal, FileSystemException se plantea.

Sin embargo, esto parece muy kludgey y podría no ser fiable en otros sistemas operativos.

 22
Author: erickson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:46:54

Reuní una lista de caracteres de nombre de archivo ilegales (teniendo en cuenta los sistemas UNIX, Mac OS X y Windows) basada en una investigación 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é, que esto es no es una solución completa: como un comentarista señaló, a pesar de que pasa esta prueba su nombre de archivo todavía podría ser una palabra clave específica de Windows como COM, PRN, etc. Sin embargo, si el nombre del archivo contiene alguno de estos caracteres, sin duda causará problemas en un entorno multiplataforma.

 57
Author: Zsolt Török,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-30 15:04:28

Aquí se sugiere la 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;
  }
}
 17
Author: Maxim Mazin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-04 15:24:39

Si se está desarrollando para Eclipse, echa un vistazo a 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;
   }
}
 5
Author: Nick J. R. T.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-11 21:10:42

Así es como implementé esto:

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;
}
 4
Author: Mosty Mostacho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-27 00:27:52

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.

 3
Author: svachon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-21 18:00:53

Solo algo que encontré, en Java 7 y más tarde, hay una clase llamada Paths que tiene un método llamado get que toma uno o más String s y lanza

InvalidPathException - si la cadena de ruta no se puede convertir en una ruta

 3
Author: BrainStorm.exe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-06 20:35:44

Usando

String validName = URLEncoder.encode( fileName , "UTF-8");

File newFile = new File( validName );

Hace el trabajo.

Acabo de encontrar hoy. No estoy seguro de si funciona el 100% del tiempo, pero hasta ahora, he sido capaz de crear nombres de archivo válidos.

 0
Author: OscarRyz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-26 17:46:03