Diferença entre File.separator e barra nos caminhos

200

Qual é a diferença entre usar File.separatore normal /em uma Java Path-String?

Em contraste com a \\independência da plataforma com duas barras invertidas , parece não ser o motivo, pois as duas versões funcionam no Windows e no Unix.

public class SlashTest {
    @Test
    public void slash() throws Exception {
        File file = new File("src/trials/SlashTest.java");
        assertThat(file.exists(), is(true));
    }

    @Test
    public void separator() throws Exception {
        File file = new File("src" + File.separator + "trials" + File.separator + "SlashTest.java");
        assertThat(file.exists(), is(true));
    }
}

Para reformular a pergunta, se /funciona no Unix e no Windows, por que alguém deveria querer usá-lo File.separator?

Joe23
fonte
5
@Ring 'razões históricas' como o quê?
Marquês de Lorne

Respostas:

246

Com as bibliotecas Java para lidar com arquivos, você pode usar com segurança /(barra, não barra invertida) em todas as plataformas. O código da biblioteca manipula a tradução de coisas em caminhos específicos da plataforma internamente.

Você pode querer usar File.separatorna interface do usuário, no entanto, porque é melhor mostrar às pessoas o que fará sentido no sistema operacional e não o que faz sentido para o Java.

Atualização : em cinco minutos de pesquisa, não consegui encontrar o comportamento "você sempre pode usar uma barra" documentado. Agora, tenho certeza de que já o vi documentado, mas, na falta de encontrar uma referência oficial (porque minha memória não é perfeita), eu continuaria usando, File.separatorporque você sabe que isso funcionará.

TJ Crowder
fonte
2
Isso também pode ser um problema com o desempenho, pois você espera que o separador seja convertido em outra coisa em tempo de execução. Além disso, não espere que isso aconteça em todas as JVMs não suportadas por aí.
jpabluz
7
@TJ Crowder: "Não consegui, em cinco minutos de pesquisa, encontrar o comportamento 'você sempre pode usar uma barra' documentado." Não é um recurso da JVM, é um recurso da API do Windows NT.
Powerlord 10/03/10
12
@ Powerlord: Se o Windows também, ótimo - mas a biblioteca (não a JVM) também. Especificamente, Fileusa em FileSystem.normalizetodo o lugar para "normalizar" os caminhos recebidos por meio da API pública e praticamente qualquer coisa que lida com as cadeias de caminhos de arquivo (por exemplo FileWriter(String)) usa Filenos bastidores.
TJ Crowder
9
Desde o Java7, não é mais necessário usar o File.separator. É muito mais simples e mais limpo usar o java.nio.file.Paths (Paths.get (first, more ...)) para dir a dir e dir a associação ao nome do arquivo.
magiccrafter
6
@jpabluz 'Um problema com o desempenho'! Você está falando sério? Considerando que os nomes de arquivos de uso são colocados no disco, o impacto no tempo de execução de uma tradução é totalmente insignificante. Ele deve ser suportado por qualquer JVM, pois faz parte da especificação de File.
Marquês de Lorne #
316

Você usa File.separatorporque um dia seu programa pode ser executado em uma plataforma desenvolvida em uma região longínqua, uma terra de coisas estranhas e pessoas estranhas, onde cavalos choram e vacas operam todos os elevadores. Nesse país, as pessoas tradicionalmente usam o caractere ":" como um separador de arquivos e, de maneira tão obediente, a JVM obedece a seus desejos.

Pontudo
fonte
4
Yup, Pointy realmente nos tooks em elbonia (espero que ele não tem corte de cabelo pontudo ;-) (nerd pun dentro)
Riduidel
4
"... e vacas operam todos os elevadores." Ainda bem que eu não estava tomando um gole do meu café quando li isso. Brilhante.
TJ Crowder
8
Nesse país, você usaria a nova classe org.apache.chicken.elevators.OperatorUtility, que incorpora toda essa loucura para sua conveniência.
Cérebro
27

Embora o uso de File.separator para referenciar um nome de arquivo seja um exagero (para aqueles que imaginam países distantes, imagino que a implementação da JVM substitua a /por uma :assim como o windows jvm a substitua por a \).

No entanto, às vezes você está obtendo a referência do arquivo, não a criando, e precisa analisá-la e, para poder fazer isso, precisa conhecer o separador na plataforma. O File.separator ajuda você a fazer isso.

Yishai
fonte
11

OK, vamos inspecionar algum código.
File.javalinhas 428 a 435 em File.<init>:

String p = uri.getPath();
if (p.equals(""))
    throw new IllegalArgumentException("URI path component is empty");

// Okay, now initialize
p = fs.fromURIPath(p);
if (File.separatorChar != '/')
p = p.replace('/', File.separatorChar);

E vamos ler fs/*(FileSystem)*/.fromURIPath()documentos:

java.io.FileSystem
resumo público String fromURIPath (String path)
Pós-processo a string de caminho do URI fornecida, se necessário. Isso é usado no win32, por exemplo, para transformar "/ c: / foo" em "c: / foo". A cadeia de caminho ainda possui separadores de barra; O código na classe File os traduzirá depois que esse método retornar.

Isso significa FileSystem.fromURIPath()que o pós-processamento no caminho do URI apenas no Windows e porque na próxima linha:

p = p.replace('/', File.separatorChar);

Ele substitui cada '/' pelo dependente do sistema seperatorChar; você sempre pode ter certeza de que '/' é seguro em todos os sistemas operacionais.

Alireza Mohamadi
fonte
8

Bem, existem mais sistemas operacionais do que Unix e Windows (dispositivos portáteis, etc), e o Java é conhecido por sua portabilidade. A melhor prática é usá-lo, para que a JVM possa determinar qual é o melhor para esse SO.

jpabluz
fonte
A maioria desses SOs executa alguma variante do UNIX. Os antigos :separadores de estilo Mac já desapareceram há muito tempo. Parece que todos, menos o Windows, usam mais o padrão /. E até o Windows parece lidar com barras bem agora. Experimente cd /windows/systemum sistema Windows 10 a partir da unidade principal do sistema. Enquanto você ainda deseja exibir caminhos usando o separador do sistema (para não confundir seus usuários), basta usar a barra invertida em /qualquer outro lugar e ter certeza de que seu código funcionará em qualquer lugar em que você possa implantá-lo.
Shadow Man
7

Embora não faça muita diferença no caminho, ele faz no caminho de volta.

Claro que você pode usar '/' ou '\' no novo arquivo (caminho da string), mas File.getPath () fornecerá apenas um deles.

William Billingsley
fonte
Correção leve ... No Windows, você pode usar a barra /para frente ou para trás \\ . Mas em qualquer outro lugar, é melhor você usar a barra /ou terá problemas.
Shadow Man
6

Tarde para a festa. Estou no Windows 10 com JDK 1.8 e Eclipse MARS 1.
Acho que

getClass().getClassLoader().getResourceAsStream("path/to/resource");

trabalha e

getClass().getClassLoader().getResourceAsStream("path"+File.separator+"to"+File.separator+"resource");

não funciona e

getClass().getClassLoader().getResourceAsStream("path\to\resource");

não funciona. Os dois últimos são equivalentes. Então ... Eu tenho um bom motivo para NÃO usar o File.separator.

eu-faço-robôs
fonte
6
Nesta linha getClass().getClassLoader().getResourceAsStream("path\to\resource");, há uma tabulação ( \t) e um retorno de carro ( \r).
Stephan
9
Esse é um cenário diferente para a pergunta. O método getResourceAsStream do ClassLoader não aceita um caminho de arquivo, mas um nome de recurso que pode ou não estar no sistema de arquivos e está documentado como apenas aceitando '/' como separador de caminho de recurso.
Daiscog
@ Stefan, não há graça em escapar por lá, pois File.separatoré uma barra invertida. É apenas em cadeias codificadas, onde é tratado como um caractere de escape, onde você precisa escapar da barra invertida. Se você armazenou o caractere em um arquivo de texto ou em um arquivo charou Stringentão não precisa escapá-lo pela segunda vez, pois ele já foi convertido no caractere de barra invertida esperado. Tente isso para ver por si mesmo:String backslash = "\\"; System.out.println("welcome" + backslash + "to" + backslash + "reality");
Shadow Man
2
@ Stephan oh, entendo ... Você estava falando sobre a terceira linha. Você está certo. Nessa linha (uma sequência codificada), você precisaria escapar do caractere de escape. Meus olhos pararam na segunda linha e eu nem percebi a terceira linha no início.
Shadow Man
3

portabilidade pura e simples.

Holograham
fonte
Sim, para portabilidade, não use barra invertida. Use barra /ou o separador do sistema File.separator. Ambos parecem funcionar em todos os lugares. Embora File.separatorseja garantido que funcione em qualquer lugar, a barra simples /também parece funcionar em qualquer lugar. Se não funcionar em algum lugar, eu adoraria ouvir sobre isso. Eu acredito que funcionará em todos os sistemas. No mínimo, ainda não encontrei nenhum lugar que /não funcione (Mac OSX, Windows, * nix, Android, iOS - ainda não verifiquei os Macs OSX anteriores que usavam ":" como separador, embora OS / 2, NeXT ou qualquer outro sistema operacional realmente antigo).
Shadow Man
1

O "Java SE8 for Programmers" afirma que o Java vai lidar com eles. (p. 480, último parágrafo). O exemplo afirma que:

c:\Program Files\Java\jdk1.6.0_11\demo/jfc

irá analisar muito bem. Anote o último separador (estilo Unix).

É brega e provavelmente suscetível a erros, mas é o que eles (Deitel e Deitel) afirmam.

Eu acho que a confusão para as pessoas, ao invés de Java, é motivo suficiente para não usar esse recurso (mis?).

Erik Bennett
fonte
1

Como os cavalheiros descreveram a diferença com detalhes variantes.

Gostaria de recomendar o uso da classe Apache Commons io api, FilenameUtilsao lidar com arquivos em um programa com a possibilidade de implantar em vários sistemas operacionais.

EX
fonte
0

O nome do caminho de um arquivo ou diretório é especificado usando as convenções de nomenclatura do sistema host. No entanto, a classe File define constantes dependentes da plataforma que podem ser usadas para manipular nomes de arquivos e diretórios de maneira independente da plataforma.

Files.seperator define o caractere ou string que separa o diretório e os componentes do arquivo em um nome de caminho. Este separador é '/', '\' ou ':' para Unix, Windows e Macintosh, respectivamente.

shubhankar
fonte
O ":" para Macintosh é antigo. Desde o OSX, o Mac também usa "/" (barra), pois está executando uma forma de UNIX com um sistema de arquivos UNIX padrão sob o capô.
Shadow Man
0

O uso do File.separator fez o Ubuntu gerar arquivos com "\" no nome, em vez de diretórios. Talvez eu esteja sendo preguiçoso com a forma como estou criando arquivos (e diretórios) e possa ter evitado isso, independentemente, use "/" sempre para evitar arquivos com "\" no nome

Guedez
fonte
0

Se você está tentando criar um arquivo a partir de um caminho pronto (salvo no banco de dados, por exemplo) usando o separador Linux, o que devo fazer?

Talvez apenas use o caminho para criar o arquivo:

new File("/shared/folder/file.jpg");

Mas o Windows usa um separador diferente ( \). Então, a alternativa é converter o separador de barra em plataforma independente? Gostar:

new File(convertPathToPlatformIndependent("/shared/folder"));

Esse método convertPathToPlatformIndependentprovavelmente terá algum tipo de divisão por "/" e se juntará ao File.separator.

Bem, para mim, isso não é bom para uma linguagem independente de plataforma (certo?) E o Java já suporta o uso /no Windows ou Linux. Mas se você estiver trabalhando com caminhos e precisar se lembrar dessa conversão todas as vezes, isso será um pesadelo e você não terá nenhum ganho real para a aplicação no futuro (talvez no universo que o @Pointy descreveu).

Dherik
fonte