API do caminho Java NIO2
1. Visão geral
Neste artigo, aprenderemos como usar a nova API I / O (NIO2)Path em Java.
As APIsPath no NIO2 constituem uma das principais novas áreas funcionais que acompanham o Java 7 e, especificamente, um subconjunto da nova API do sistema de arquivos junto com as APIs de arquivo.
2. Configuração
O suporte NIO2 está incluído no pacotejava.nio.file. Portanto, configurar seu projeto para usar as APIsPath é apenas uma questão de importar tudo neste pacote:
import java.nio.file.*;
Como os exemplos de código neste artigo provavelmente serão executados em ambientes diferentes, vamos controlar o diretório inicial do usuário:
private static String HOME = System.getProperty("user.home");
Essa variável apontará para um local válido em qualquer ambiente.
A classePaths é o principal ponto de entrada para todas as operações que envolvem caminhos do sistema de arquivos. Ele nos permite criar e manipular caminhos para arquivos e diretórios.
Digno de nota é que as operações de caminho são principalmente de natureza sintática; eles não têm efeito no sistema de arquivos subjacente e o sistema de arquivos não tem nenhum efeito sobre o êxito ou a falha. Isso significa que a passagem de um caminho inexistente como parâmetro de uma operação de caminho não tem influência se é bem-sucedida ou falha.
3. Operações de Caminho
Nesta seção, apresentaremos a principal sintaxe usada nas operações de caminho. Como o próprio nome indica, a classePath é uma representação programática de um caminho no sistema de arquivos.
Um objetoPath contém o nome do arquivo e a lista de diretórios usados para construir o caminho e é usado para examinar, localizar e manipular arquivos.
A classe auxiliar,java.nio.file.Paths (no plural) é a maneira formal de criar objetosPath. Ele tem dois métodos estáticos para criar umPath a partir de uma string de caminho:
Path path = Paths.get("path string");
Não importa se usamos uma barra para frente ou para trás no caminhoString,, a API resolve esse parâmetro de acordo com os requisitos do sistema de arquivos subjacente.
E de um objetojava.net.URI:
Path path = Paths.get(URI object);
Agora podemos ir em frente e vê-los em ação.
4. Criando um Caminho
Para o objetocreate a Path de uma string de caminho:
@Test
public void givenPathString_whenCreatesPathObject_thenCorrect() {
Path p = Paths.get("/articles/example");
assertEquals("\\articles\\example", p.toString());
}
A APIget pode aceitar um parâmetro de argumentos variáveis das partes da string do caminho (neste caso,articleseexample), além da primeira parte (neste caso,articles )
Se fornecermos essas partes em vez de uma cadeia de caminho completa, elas serão usadas para construir o objeto Path, não precisamos incluir os separadores de nomes (barras) na parte dos argumentos da variável:
@Test
public void givenPathParts_whenCreatesPathObject_thenCorrect() {
Path p = Paths.get("/articles", "example");
assertEquals("\\articles\\example", p.toString());
}
5. Recuperando Informações do Caminho
Você pode pensar no objeto Path como elementos de nome como uma sequência. Um caminhoString, comoE:\examplerticles\java consiste em três elementos de nome, ou seja, example,articles ejava. O elemento mais alto na estrutura do diretório estaria localizado no índice 0, neste caso sendoexample.
O elemento mais baixo na estrutura do diretório estaria localizado no índice[n-1], onden é o número de elementos de nome no caminho. Este elemento inferior é chamado defile name, independentemente de ser um arquivo real ou não:
@Test
public void givenPath_whenRetrievesFileName_thenCorrect() {
Path p = Paths.get("/articles/example/logs");
Path fileName = p.getFileName();
assertEquals("logs", fileName.toString());
}
Os métodos estão disponíveis para recuperar elementos individuais por índice:
@Test
public void givenPath_whenRetrievesNameByIndex_thenCorrect() {
Path p = Paths.get("/articles/example/logs");
Path name0 = getName(0);
Path name1 = getName(1);
Path name2 = getName(2);
assertEquals("articles", name0.toString());
assertEquals("example", name1.toString());
assertEquals("logs", name2.toString());
}
ou uma sub-sequência do caminho usando esses intervalos de índice:
@Test
public void givenPath_whenCanRetrieveSubsequenceByIndex_thenCorrect() {
Path p = Paths.get("/articles/example/logs");
Path subPath1 = p.subpath(0,1);
Path subPath2 = p.subpath(0,2);
assertEquals("articles", subPath1.toString());
assertEquals("articles\\example", subPath2.toString());
assertEquals("articles\\example\\logs", p.subpath(0, 3).toString());
assertEquals("example", p.subpath(1, 2).toString());
assertEquals("example\\logs", p.subpath(1, 3).toString());
assertEquals("logs", p.subpath(2, 3).toString());
}
Cada caminho está associado a um caminho pai ounull se o caminho não tiver pai. O pai de um objeto de caminho consiste no componente raiz do caminho, se houver, e em cada elemento no caminho, exceto para o nome do arquivo. Por exemplo, o caminho pai de/a/b/c é/a/be o de/a é nulo:
@Test
public void givenPath_whenRetrievesParent_thenCorrect() {
Path p1 = Paths.get("/articles/example/logs");
Path p2 = Paths.get("/articles/example");
Path p3 = Paths.get("/articles");
Path p4 = Paths.get("/");
Path parent1 = p1.getParent();
Path parent2 = p2.getParent();
Path parent3 = p3.getParent();
Path parent4 = p4.getParenth();
assertEquals("\\articles\\example", parent1.toString());
assertEquals("\\articles", parent2.toString());
assertEquals("\\", parent3.toString());
assertEquals(null, parent4);
}
Também podemos obter o elemento raiz de um caminho:
@Test
public void givenPath_whenRetrievesRoot_thenCorrect() {
Path p1 = Paths.get("/articles/example/logs");
Path p2 = Paths.get("c:/articles/example/logs");
Path root1 = p1.getRoot();
Path root2 = p2.getRoot();
assertEquals("\\", root1.toString());
assertEquals("c:\\", root2.toString());
}
6. Normalizando um Caminho
Muitos sistemas de arquivos usam a notação“.” para denotar o diretório atual e“..” para denotar o diretório pai. Você pode ter uma situação em que um caminho contém informações de diretório redundantes.
Por exemplo, considere as seguintes cadeias de caminho:
/example/./articles
/example/authors/../articles
/example/articles
Todos eles resolvem para o mesmo local/example/articles. Os dois primeiros têm redundâncias, enquanto o último não.
Normalizar um caminho envolve remover redundâncias nele. A operaçãoPath.normalize() é fornecida para esse propósito.
Este exemplo agora deve ser auto-explicativo:
@Test
public void givenPath_whenRemovesRedundancies_thenCorrect1() {
Path p = Paths.get("/home/./example/articles");
Path cleanPath = p.normalize();
assertEquals("\\home\\example\\articles", cleanPath.toString());
}
Esse também:
@Test
public void givenPath_whenRemovesRedundancies_thenCorrect2() {
Path p = Paths.get("/home/example/../articles");
Path cleanPath = p.normalize();
assertEquals("\\home\\articles", cleanPath.toString());
}
7. Conversão de Caminho
Existem operações para converter um caminho em um formato de apresentação escolhido. Para converter qualquer caminho em uma string que pode ser aberta no navegador, usamos o métodotoUri:
@Test
public void givenPath_whenConvertsToBrowseablePath_thenCorrect() {
Path p = Paths.get("/home/example/articles.html");
URI uri = p.toUri();
assertEquals(
"file:///E:/home/example/articles.html",
uri.toString());
}
Também podemos converter um caminho para sua representação absoluta. O métodotoAbsolutePath resolve um caminho em um diretório padrão do sistema de arquivos:
@Test
public void givenPath_whenConvertsToAbsolutePath_thenCorrect() {
Path p = Paths.get("/home/example/articles.html");
Path absPath = p.toAbsolutePath();
assertEquals(
"E:\\home\\example\\articles.html",
absPath.toString());
}
No entanto, quando o caminho a ser resolvido for detectado como já absoluto, o método o retornará como é:
@Test
public void givenAbsolutePath_whenRetainsAsAbsolute_thenCorrect() {
Path p = Paths.get("E:\\home\\example\\articles.html");
Path absPath = p.toAbsolutePath();
assertEquals(
"E:\\home\\example\\articles.html",
absPath.toString());
}
Também podemos converter qualquer caminho em seu equivalente real chamando o métodotoRealPath. Este método tenta resolver o caminho mapeando seus elementos para diretórios e arquivos reais no sistema de arquivos.
É hora de usar a variável que criamos na seçãoSetup que aponta para a localização inicial do usuário conectado no sistema de arquivos:
@Test
public void givenExistingPath_whenGetsRealPathToFile_thenCorrect() {
Path p = Paths.get(HOME);
Path realPath = p.toRealPath();
assertEquals(HOME, realPath.toString());
}
O teste acima não nos diz muito sobre o comportamento desta operação. O resultado mais óbvio é que, se o caminho não existir no sistema de arquivos, a operação lançará umIOException, continue lendo.
Para a falta de uma maneira melhor de levar esse ponto para casa, basta dar uma olhada no próximo teste, que tenta converter um caminho inexistente em um caminho real:
@Test(expected = NoSuchFileException.class)
public void givenInExistentPath_whenFailsToConvert_thenCorrect() {
Path p = Paths.get("E:\\home\\example\\articles.html");
p.toRealPath();
}
O teste é bem-sucedido quando pegamos umIOException. A subclasse real deIOException que esta operação lança éNoSuchFileException.
8. Caminhos de união
A união de quaisquer dois caminhos pode ser obtida usando o métodoresolve.
Simplificando, podemos chamar o métodoresolve em qualquerPathe passarpartial path como argumento. Esse caminho parcial é anexado ao caminho original:
@Test
public void givenTwoPaths_whenJoinsAndResolves_thenCorrect() {
Path p = Paths.get("/example/articles");
Path p2 = p.resolve("java");
assertEquals("\\example\\articles\\java", p2.toString());
}
No entanto, quando a string de caminho passada para o métodoresolve não é umpartial path; mais notavelmente um caminho absoluto, o caminho passado é retornado:
@Test
public void givenAbsolutePath_whenResolutionRetainsIt_thenCorrect() {
Path p = Paths.get("/example/articles");
Path p2 = p.resolve("C:\\example\\articles\java");
assertEquals("C:\\example\\articles\\java", p2.toString());
}
O mesmo acontece com qualquer caminho que tenha um elemento raiz. A string de caminho“java” não tem elemento raiz, enquanto a string de caminho“/java” tem um elemento de raiz. Portanto, quando você passa um caminho com um elemento raiz, ele é retornado como está:
@Test
public void givenPathWithRoot_whenResolutionRetainsIt_thenCorrect2() {
Path p = Paths.get("/example/articles");
Path p2 = p.resolve("/java");
assertEquals("\\java", p2.toString());
}
9. Relativizing caminhos
O termorelativizing significa simplesmente criar um caminho direto entre dois caminhos conhecidos. Por exemplo, se temos um diretório/examplee dentro dele, temos dois outros diretórios, tais como/example/authorse/example/articles são caminhos válidos.
O caminho paraarticles em relação aauthors seria descrito como“move one level up in the directory hierarchy then into articles directory” ou..rticles:
@Test
public void givenSiblingPaths_whenCreatesPathToOther_thenCorrect() {
Path p1 = Paths.get("articles");
Path p2 = Paths.get("authors");
Path p1_rel_p2 = p1.relativize(p2);
Path p2_rel_p1 = p2.relativize(p1);
assertEquals("..\\authors", p1_rel_p2.toString());
assertEquals("..\\articles", p2_rel_p1.toString());
}
Supondo que movamos o diretórioarticles para a pastaauthors de forma que eles não sejam mais irmãos. As seguintes operações de relativização envolvem a criação de um caminho entreexampleearticles e vice-versa:
@Test
public void givenNonSiblingPaths_whenCreatesPathToOther_thenCorrect() {
Path p1 = Paths.get("/example");
Path p2 = Paths.get("/example/authors/articles");
Path p1_rel_p2 = p1.relativize(p2);
Path p2_rel_p1 = p2.relativize(p1);
assertEquals("authors\\articles", p1_rel_p2.toString());
assertEquals("..\\..", p2_rel_p1.toString());
}
10. Comparando Caminhos
A classePath tem uma implementação intuitiva do métodoequals que nos permite comparar dois caminhos para igualdade:
@Test
public void givenTwoPaths_whenTestsEquality_thenCorrect() {
Path p1 = Paths.get("/example/articles");
Path p2 = Paths.get("/example/articles");
Path p3 = Paths.get("/example/authors");
assertTrue(p1.equals(p2));
assertFalse(p1.equals(p3));
}
Você também pode verificar se um caminho começa com uma determinada sequência:
@Test
public void givenPath_whenInspectsStart_thenCorrect() {
Path p1 = Paths.get("/example/articles");
assertTrue(p1.startsWith("/example"));
}
Ou termina com outra string:
@Test
public void givenPath_whenInspectsEnd_thenCorrect() {
Path p1 = Paths.get("/example/articles");
assertTrue(p1.endsWith("articles"));
}
11. Conclusão
Neste artigo, mostramos as operações do Path na nova API do sistema de arquivos (NIO2), que foi enviada como parte do Java 7 e que a maioria delas estava em ação.
Os exemplos de código usados neste artigo podem ser encontrados emGithub project do artigo.