Um guia para APIs de atributo de arquivo NIO2

Um guia para APIs de atributo de arquivo NIO2

1. Visão geral

Neste artigo, exploraremos um dos recursos avançados das APIs do sistema de arquivos Java 7 NIO.2 - especificamente as APIs de atributo de arquivo.

Já cobrimosFile ePath APIs se você quiser se aprofundar nessas peças fundamentais primeiro.

Todos os arquivos necessários para lidar com as operações do sistema de arquivos estão agrupados emjava.nio.file package:

import java.nio.file.*;

2. Atributos de arquivo básicos

Vamos começar com uma visão de alto nível dos atributos básicos comuns a todos os sistemas de arquivos - fornecidos peloBasicFileAttributeView - que armazena todos os atributos de arquivo visíveis obrigatórios e opcionais.

Podemos explorar os atributos básicos da localização inicial do usuário na máquina atual, criando um caminho para HOME e obtendo sua visualização de atributos básicos:

String HOME = System.getProperty("user.home");
Path home = Paths.get(HOME);
BasicFileAttributeView basicView =
  Files.getFileAttributeView(home, BasicFileAttributeView.class);

Após a etapa acima, agora podemos ler todos os atributos do caminho apontado em uma operação em massa:

BasicFileAttributes basicAttribs = basicView.readAttributes();

Agora estamos em posição de explorar diferentes atributos comuns que podemos realmente usar em nossos aplicativos, especialmente em declarações condicionais.

Podemos consultar o tamanho do arquivo em seu contêiner de atributos básicos:

@Test
public void givenPath_whenGetsFileSize_thenCorrect() {
    long size = basicAttribs.size();
    assertTrue(size > 0);
}

Também podemos verificar se é um diretório:

@Test
public void givenPath_whenChecksIfDirectory_thenCorrect() {
    boolean isDir = basicAttribs.isDirectory();
    assertTrue(isDir);
}

Ou um arquivo regular:

@Test
public void givenPath_whenChecksIfFile_thenCorrect() {
    boolean isFile = basicAttribs.isRegularFile();
    assertFalse(isFile);
}

Com o Java NIO.2, agora podemos lidar com links simbólicos ou soft links no sistema de arquivos. Esses são arquivos ou diretórios que normalmente chamamos de atalhos.

Para verificar se um arquivo é um link simbólico:

@Test
public void givenPath_whenChecksIfSymLink_thenCorrect() {
    boolean isSymLink = basicAttribs.isSymbolicLink();
    assertFalse(isSymLink);
}

Em casos raros, podemos chamar a APIisOther para verificar se o arquivo não pertence a nenhuma das categorias comuns de arquivo regular, diretório ou link simbólico:

@Test
public void givenPath_whenChecksIfOther_thenCorrect() {
    boolean isOther = basicAttribs.isOther();
    assertFalse(isOther);
}

Para obter a hora em que o arquivo foi criado:

FileTime created = basicAttribs.creationTime();

Para obter a hora da última modificação:

FileTime modified = basicAttribs.lastModifiedTime();

E para obter o último horário de acesso:

FileTime accessed = basicAttribs.lastAccessTime();

Todos os exemplos acima retornam um objetoFileTime. Esta é uma abstração mais utilizável do que um mero carimbo de data e hora.

Por exemplo, podemos comparar facilmente dois tempos de arquivo para saber qual evento ocorreu antes ou depois do outro:

@Test
public void givenFileTimes_whenComparesThem_ThenCorrect() {
    FileTime created = basicAttribs.creationTime();
    FileTime modified = basicAttribs.lastModifiedTime();
    FileTime accessed = basicAttribs.lastAccessTime();

    assertTrue(0 >= created.compareTo(accessed));
    assertTrue(0 <= modified.compareTo(created));
    assertTrue(0 == created.compareTo(created));
}

A APIcompareTo funciona da mesma maneira que outras comparáveis ​​em Java. Ele retorna um valor negativo caso o objeto que está sendo chamado seja menor que o argumento; em nosso caso, o tempo de criação definitivamente vem antes do tempo de acesso, como na primeira asserção.

Na segunda asserção, obtemos um valor inteiro positivo porque uma modificação só pode ser feita após um evento de criação. E, finalmente, retorna 0 quando os tempos comparados são iguais.

Quando temos um objeto FileTime, podemos convertê-lo na maioria das outras unidades, dependendo de nossas necessidades; dias, horas, minutos, segundos, milissegundos e assim por diante. Fazemos isso chamando a API apropriada:

accessed.to(TimeUnit.SECONDS);
accessed.to(TimeUnit.HOURS);
accessed.toMillis();

Podemos também imprimir uma forma legível por humanos da hora do arquivo chamando sua APItoString:

accessed.toString();

Que imprime algo útil no formato de hora ISO:

2016-11-24T07:52:53.376Z

Também podemos alterar os atributos de tempo na visualização chamando sua APIsetTimes(modified, accessed, created). Passamos os novos objetosFileTime onde queremos mudar ou null onde não queremos mudar.

Para alterar o horário do último acesso em um minuto, seguiremos estas etapas:

FileTime newAccessTime = FileTime.fromMillis(
  basicAttribs.lastAccessTime().toMillis() + 60000);
basicView.setTimes(null, newAccessTime , null);

Essa alteração persistirá no arquivo real, como visto em qualquer outro aplicativo em execução na máquina e no sistema de arquivos.

3. Atributos de espaço de arquivo

Quando você abremy computer no Windows, Linux ou Mac, geralmente pode ver uma análise gráfica das informações de espaço sobre suas unidades de armazenamento.

O Java NIO.2 facilita muito esse tipo de funcionalidade de alto nível. Ele interage com o sistema de arquivos subjacente para recuperar essas informações, enquanto apenas precisamos chamar APIs simples.

Podemos usar a classeFileStore para inspecionar unidades de armazenamento e obter informações importantes, como seu tamanho, quanto espaço é usado e quanto ainda não é usado.

Para obter uma instânciaFileStore para a localização de um arquivo arbitrário no sistema de arquivos, usamos a APIgetFileStore da classeFiles:

Path file = Paths.get("file");
FileStore store = Files.getFileStore(file);

Esta instânciaFileStore representa especificamente o armazenamento de arquivos onde o arquivo especificado está localizado, não o arquivo em si. Para obter espaço total:

long total = store.getTotalSpace();

Para se acostumar com o espaço:

long used = store.getTotalSpace() - store.getUnallocatedSpace();

É menos provável que sigamos essa abordagem do que a próxima.

Mais comumente, é provável que obtenhamos informações sobre informações de armazenamento sobre todos os armazenamentos de arquivos. Para emularmy computer's informações de espaço da unidade gráfica em um programa, podemos usar a classeFileSystem para enumerar os armazenamentos de arquivos:

Iterable fileStores = FileSystems.getDefault().getFileStores();

Em seguida, podemos fazer um loop sobre os valores retornados e fazer o que for necessário com as informações, como atualizar uma interface gráfica do usuário:

for (FileStore fileStore : fileStores) {
    long totalSpace = fileStore.getTotalSpace();
    long unAllocated = fileStore.getUnallocatedSpace();
    long usable = fileStore.getUsableSpace();
}

Observe que todos os valores retornados estão em bytes. Podemos converter em unidades adequadas, além de calcular outras informações, como espaço usado, usando aritmética básica.

The difference between unallocated space and usable space está em acessibilidade à JVM.

Espaço útil é o espaço disponível para a JVM, enquanto espaço não alocado é o espaço disponível, conforme visto pelo sistema de arquivos subjacente. Portanto, o espaço utilizável às vezes pode ser menor que o espaço não alocado.

4. Atributos do proprietário do arquivo

Para inspecionar as informações de propriedade do arquivo, usamos a interfaceFileOwnerAttributeView. Ele nos fornece uma visão de alto nível das informações de propriedade.

Podemos criar um objetoFileOwnerAttributeView assim:

Path path = Paths.get(HOME);
FileOwnerAttributeView ownerView = Files.getFileAttributeView(
  attribPath, FileOwnerAttributeView.class);

Para obter o proprietário do arquivo na exibição acima:

UserPrincipal owner = ownerView.getOwner();

Não há realmente nada que possamos fazer programaticamente com o objeto acima, além de obter o nome do proprietário para algum outro propósito arbitrário:

String ownerName = owner.toString();

5. Atributos de arquivo definidos pelo usuário

Existem cenários em que os atributos de arquivo definidos no sistema de arquivos não são suficientes para suas necessidades. Se você se deparar com esse caso e precisar definir seus próprios atributos em um arquivo, a interfaceUserDefinedFileAttributeView será útil:

Path path = Paths.get("somefile");
UserDefinedFileAttributeView userDefView = Files.getFileAttributeView(
  attribPath, UserDefinedFileAttributeView.class);

Para recuperar a lista de atributos definidos pelo usuário já definidos para o arquivo representado pela visualização acima:

List attribList = userDefView.list();

Para definir um atributo definido pelo usuário no arquivo, usamos o seguinte idioma:

String name = "attrName";
String value = "attrValue";
userDefView.write(name, Charset.defaultCharset().encode(value));

Quando você precisar acessar os atributos definidos pelo usuário, poderá percorrer a lista de atributos retornada pela visualização e inspecioná-los usando este idioma:

ByteBuffer attrValue = ByteBuffer.allocate(userView.size(attrName));
userDefView.read(attribName, attribValue);
attrValue.flip();
String attrValue = Charset.defaultCharset().decode(attrValue).toString();

Para remover um atributo definido pelo usuário do arquivo, simplesmente chamamos a API de exclusão da exibição:

userDefView.delete(attrName);

6. Conclusão

Neste artigo, exploramos alguns dos recursos menos usados ​​disponíveis nas APIs do sistema de arquivos Java 7 NIO.2, especificamente as APIs de atributo de arquivo.

O código-fonte completo dos exemplos usados ​​neste artigo está disponível emGithub project.