Qual é a diferença entre getPath (), getAbsolutePath () e getCanonicalPath () em Java?

583

Qual é a diferença entre getPath(), getAbsolutePath()e getCanonicalPath()em Java?

E quando eu uso cada um?

knt
fonte
Não esqueça Path.toAbsolutePath().normalize()qual é um bom meio termo entre o caminho canônico (real) e o caminho absoluto sozinho.
Eckes

Respostas:

625

Considere estes nomes de arquivos:

C:\temp\file.txt - Este é um caminho, um caminho absoluto e um caminho canônico.

.\file.txt- Este é um caminho. Não é um caminho absoluto nem um caminho canônico.

C:\temp\myapp\bin\..\\..\file.txt- Este é um caminho e um caminho absoluto. Não é um caminho canônico.

Um caminho canônico é sempre um caminho absoluto.

A conversão de um caminho para um caminho canônico o torna absoluto (geralmente adere ao diretório de trabalho atual, por exemplo, ./file.txttorna-se c:/temp/file.txt). O caminho canônico de um arquivo apenas "purifica" o caminho, removendo e resolvendo coisas como ..\e resolvendo links simbólicos (em unixes).

Observe também o exemplo a seguir com nio.Paths:

String canonical_path_string = "C:\\Windows\\System32\\";
String absolute_path_string = "C:\\Windows\\System32\\drivers\\..\\";

System.out.println(Paths.get(canonical_path_string).getParent());
System.out.println(Paths.get(absolute_path_string).getParent());

Enquanto os dois caminhos se referem ao mesmo local, a saída será bem diferente:

C:\Windows
C:\Windows\System32\drivers
n
fonte
11
FWIW, não é um dado C:\temp\file.txtcanônico - o diretório temporário pode ser um link flexível do sistema de arquivos ou um link físico (uma junção no NTFS), e file.txt pode ser um link flexível. Não sei se os sistemas de arquivos podem distinguir links físicos para arquivos.
Lawrence Dol
1
O caminho não considera realmente esses problemas ou a existência de nenhum dos componentes, apenas a sintaxe.
escape-llc
Sim, o caminho canônico (diferente do caminho normalizado) atinge o sistema de arquivos.
Eckes
1
Basicamente, não vejo uma razão pela qual alguém deva usar em getAbsolutePath()vez de getCanonicalPath(). Até parece melhor porque o canônico resolve essas ../partes automaticamente .
Scadge
Não se esqueça que getCanonicalPathjoga um IOExceptiontempo getAbsolutePathnão, se isso é uma consideração.
Carrinho abandonado
129

A melhor maneira que encontrei para experimentar coisas assim é experimentá-las:

import java.io.File;
public class PathTesting {
    public static void main(String [] args) {
        File f = new File("test/.././file.txt");
        System.out.println(f.getPath());
        System.out.println(f.getAbsolutePath());
        try {
            System.out.println(f.getCanonicalPath());
        }
        catch(Exception e) {}
    }
}

Sua saída será algo como:

test\..\.\file.txt
C:\projects\sandbox\trunk\test\..\.\file.txt
C:\projects\sandbox\trunk\file.txt

Portanto, getPath()fornece o caminho com base no objeto File, que pode ou não ser relativo; getAbsolutePath()fornece um caminho absoluto para o arquivo; egetCanonicalPath() fornece o caminho absoluto exclusivo para o arquivo. Observe que há um grande número de caminhos absolutos que apontam para o mesmo arquivo, mas apenas um caminho canônico.

Quando usar cada um? Depende do que você está tentando realizar, mas se você está tentando ver se dois Filesestão apontando para o mesmo arquivo no disco, você pode comparar seus caminhos canônicos. Apenas um exemplo.

dave4351
fonte
7
É discutível que Java tenha entendido errado a implementação de um caminho "absoluto"; realmente deveria ter removido qualquer elemento relativo do caminho em um caminho absoluto. A forma canônica removeria todos os links ou junções FS no caminho.
Lawrence Dol
but if you were trying to see if two Files are pointing at the same file on diskQuão? exemplo por favor?
Asif Mushtaq
@ Desconhecido: Você usaria o caminho canônico para isso.
Lawrence Dol
67

Em resumo:

  • getPath()obtém a cadeia de caminho com a qual o Fileobjeto foi construído e pode ser o diretório atual relativo.
  • getAbsolutePath() obtém a sequência do caminho após resolvê-la no diretório atual, se for relativo, resultando em um caminho completo.
  • getCanonicalPath()obtém a cadeia de caminho após resolver qualquer caminho relativo no diretório atual e remove qualquer caminho relativo ( .e ..) e qualquer link do sistema de arquivos para retornar um caminho que o sistema de arquivos considera os meios canônicos para referenciar o objeto do sistema de arquivos para o qual aponta.

Além disso, cada um deles possui um arquivo equivalente, que retorna o Fileobjeto correspondente .

Lawrence Dol
fonte
36

getPath()retorna o caminho usado para criar o Fileobjeto. Esse valor de retorno não é alterado com base no local em que é executado (os resultados abaixo são para janelas, os separadores são obviamente diferentes em outros lugares)

File f1 = new File("/some/path");
String path = f1.getPath(); // will return "\some\path"

File dir = new File("/basedir");
File f2 = new File(dir, "/some/path");
path = f2.getPath(); // will return "\basedir\some\path"

File f3 = new File("./some/path");
path = f3.getPath(); // will return ".\some\path"

getAbsolutePath()resolverá o caminho com base no local de execução ou na unidade. Portanto, se executado a partir de c:\test:

path = f1.getAbsolutePath(); // will return "c:\some\path"
path = f2.getAbsolutePath(); // will return "c:\basedir\some\path"
path = f3.getAbsolutePath(); // will return "c:\test\.\basedir\some\path"

getCanonicalPath()depende do sistema. Ele resolverá o local exclusivo que o caminho representa. Portanto, se você tiver algum "." S no caminho, eles normalmente serão removidos.

Quanto a quando usá-los. Depende do que você está tentando alcançar. getPath()é útil para portabilidade. getAbsolutePath()é útil para encontrar o local do sistema de arquivos e getCanonicalPath()é particularmente útil para verificar se dois arquivos são iguais.

Vendedor rico
fonte
você pode me dar um exemplo disso? getCanonicalPath() is particularly useful to check if two files are the same.
Asif Mushtaq
20

O mais importante é que a Fileclasse tenta representar uma visão do que a Sun gosta de chamar de "nomes de caminhos hierárquicos" (basicamente um caminho como c:/foo.txtou /usr/muggins). É por isso que você cria arquivos em termos de caminhos. As operações que você está descrevendo são todas operações sobre esse "nome do caminho".

  • getPath()busca o caminho com o qual o arquivo foi criado ( ../foo.txt)
  • getAbsolutePath()busca o caminho com o qual o arquivo foi criado, mas inclui informações sobre o diretório atual se o caminho for relativo ( /usr/bobstuff/../foo.txt)
  • getCanonicalPath() tenta buscar uma representação exclusiva do caminho absoluto para o arquivo. Isso elimina a indireção de ".." e "." referências ( /usr/foo.txt).

Note que digo tentativas - ao formar um caminho canônico, a VM pode lançar um IOException. Isso geralmente ocorre porque está executando algumas operações do sistema de arquivos, qualquer uma das quais pode falhar.

manteiga
fonte
3

Acho que raramente preciso usar getCanonicalPath(), mas, se for fornecido um arquivo com um nome de arquivo no formato DOS 8.3 no Windows, como a java.io.tmpdirpropriedade System retorna, esse método retornará o nome de arquivo "completo".

Matthew Wise
fonte