Pergunta

Na minha aplicação Java que eu estou renomeando os arquivos para um nome de arquivo fornecido em um parâmetro de cadeia. Existe um método

boolean OKtoRename(String oldName, String newName)

O que basicamente verifica se o newName não estiver tomada por algum outro arquivo, como eu não gostaria de enterrar os já existentes.

Agora, ocorreu-me que talvez a Cadeia newName não vai designar um nome de arquivo válido. Então eu pensei para adicionar esta seleção para o método:

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

O que obviamente não é o caminho certo para fazê-lo, uma vez que na maioria dos casos, o newFile ainda não existe e, portanto, embora é OKtoRename, a função retorna falso.

Eu estava pensando, existe um método (eu sei que não é para o java.io.File objetos) como canExist()? Ou eu teria que recorrer a regex para certificar-se da Cadeia newFile não contém caracteres inválidos (por exemplo,?, *,", :)? Eu me pergunto se há talvez uma função escondida em algum lugar no JDK que me dizer se uma string poderia indicar um nome de arquivo válido.

Foi útil?

Solução

Use createNewFile() , que irá atomicamente criar o arquivo apenas se ele ainda não existe.

Se o arquivo é criado, o nome é válido e não se sobrepor um arquivo existente. Você pode abrir os arquivos e copiar eficientemente dados de um para o outro com operações FileChannel.transferXXX.

Uma coisa importante a ter em mente que, em geral, a verificação ea criação deve ser atômica. Se você verificar primeiro se uma operação é segura, em seguida, executar a operação como uma etapa separada, as condições podem ter mudado nesse meio tempo, tornando o funcionamento de risco.

alimento adicional para o pensamento está disponível neste post relacionado: "/ operações Mover Copiar em Java. "


Atualização:

Uma vez que esta resposta, as APIs NIO.2 foram introduzidas, que adicionar mais interação com o sistema de arquivos.

Suponha que você tenha um programa interativo, e deseja validar após cada keystroke se o arquivo é potencialmente válido. Por exemplo, você pode querer habilitar um botão "Save" apenas quando a entrada é válida em vez de aparecendo um diálogo de erro depois de pressionar "Salvar". Criando e garantir a exclusão de um monte de arquivos desnecessários que minha sugestão acima exigiria parece ser uma confusão.

Com NIO.2, você não pode criar uma instância Path contendo caracteres que são ilegais no sistema de arquivos. Um InvalidPathException é levantada assim que você tentar criar o Path.

No entanto, não há uma API para validar nomes ilegais compostos por caracteres válidos, como "PRN" no Windows. Como solução, a experimentação mostrou que o uso de um nome de arquivo ilegal iria levantar uma exceção distinta quando se tenta acessar atributos (usando Files.getLastModifiedTime(), por exemplo).

Se você especificar um nome legal para um arquivo que não existe, você recebe nenhuma exceção.

Se você especificar um nome legal para um arquivo que não existe, ele levanta NoSuchFileException.

Se você especificar um nome ilegal, FileSystemException é levantada.

No entanto, isso parece muito kludgey e pode não ser confiável em outros sistemas operacionais.

Outras dicas

Eu montei uma lista de caracteres de nome de arquivo ilegais (considerando UNIX, Mac OS X e sistemas Windows) com base em uma pesquisa online um par de meses atrás. Se o novo nome do arquivo contém qualquer destes, há um risco de que ele pode não ser válida em todas as plataformas.

private static final char[] ILLEGAL_CHARACTERS = { '/', '\n', '\r', '\t', '\0', '\f', '`', '?', '*', '\\', '<', '>', '|', '\"', ':' };

EDIT: Gostaria de stress, que esta não é uma solução completa : como um comentarista apontou, mesmo que ele passa este teste o seu nome de arquivo ainda poderia ser uma palavra-chave específica do Windows como COM, PRN, etc. no entanto, se o nome do arquivo contém qualquer um desses caracteres, ele certamente vai causar problemas em um ambiente multi-plataforma.

maneira específica sistema Aqui é sugerido.

public static boolean isFilenameValid(String file) {
  File f = new File(file);
  try {
    f.getCanonicalPath();
    return true;
  } catch (IOException e) {
    return false;
  }
}

Se a desenvolver para Eclipse, veja 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;
   }
}

Isto é como eu implementei este:

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;
}

Para mim, isso parece ser um problema dependente OS. Você pode simplesmente querer verificar se há algum caracter inválido no nome do arquivo. Windows faz isso quando você tenta mudar o nome do arquivo, ele aparece uma mensagem dizendo que um arquivo não pode conter nenhum dos seguintes caracteres: \ /: *? <> | Não tenho a certeza se a sua pergunta é "Existe uma biblioteca fazendo o trabalho para mim?" nesse caso, eu não conheço nenhum.

Apenas algo que eu encontrei, em Java 7 e, mais tarde, há uma classe chamada Paths que tem um método chamado get que leva um ou mais Strings e joga

InvalidPathException - se o cadeia de caminho não pode ser convertido para um caminho

Usando

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

File newFile = new File( validName );

faz o trabalho.

Eu só descobri hoje. Eu não tenho certeza se ele funciona 100% do tempo, mas até agora, eu tenho sido capaz de criar nomes de arquivos válidos.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top