Pular para o conteúdo principal

NIO.2 do Java 7: uma nova API do Java para file system

Uma das novidades mais importantes e aguardadas do Java 7 foi a NIO.2, a nova API para a manipulação I/O com Java. A NIO.2, também conhecida como JSR 203, disponibiliza um conjunto de novos componentes, projetados para melhorar caracterísiticas de I/O com Java como por exemplo: uma nova API para o acesso e manipulação de conteúdo do file system (sistema de arquivos); outra API para operações assíncronas com I/O; e a atualização da API para comunicação via sockets (channel sockets). 

O Java, antes da versão 7, tratava a manipulação do sistema de arquivos de forma primitiva. O programador tinha de trabalhar com a classe File para representar arquivos e/ou diretórios, com um número escasso de funcionalidades. Uma operação simples como copiar um arquivo demandava um código relativamente grande. Outras funcionalidades triviais, como por exemplo o uso de links simbólicos, não eram suportadas. Esses são alguns dos motivos para justificar o uso de bibliotecas terceiras, com funcionalidades complementares a API I/O do Java, durante o desenvolvimento de um sistema. 

API para o sistema de arquivos
No novo pacote java.nio.file estam contidos boa parte dos componentes da API para a manipulação do sistema de arquivos. Um dos pontos de partida para essa nova API é a interface Path. Ela representa o caminho hierárquico do file system de um diretório ou arquivo. Essa classe possui métodos para recuperar informações do caminho do arquivo, acessar outro elemento na estrutura hierárquica ou converter uma estrutura de diretórios.  

É possível criar um objeto Path de várias formas, uma dela é através da classe Paths (plural), uma classe helper com métodos estáticos especificos para a criação de objetos Path. O trecho de código a seguir demonstra como criar e utilizar objetos da classe Path, representando o caminho para o arquivo logo.png.
Path logo = Paths.get("/home/yaw/logo.png"); //passa o caminho completo
Path logo2 = Paths.get("/home", "yaw", "logo.png"); //outra forma

System.out.println(logo.equals(logo2));
System.out.format("%s é igual a %s? %b%n", logo, logo2, logo.equals(logo2));
System.out.format("Nome do arquivo: %s%n", logo.getFileName());
System.out.format("Qtde de elementos no path: %d%n", logo.getNameCount());
System.out.format("Volume: %s%n", logo.getRoot());
System.out.format("1o diretório: %s%n", logo.getName(0));
System.out.format("Pedaço do path (1o e 2o dir): %s%n", logo.subpath(0, 2));
System.out.format("Diretório do arquivo: %s%n", logo.getParent());
Outra opção seria criar o Path a partir do FileSystem. A classe abstrata FileSystem provê uma representação do sistema de arquivos, com funcionalidades para criar ou acessar elementos nessa estrutura. Mas para recuperar um objeto do tipo FileSystem, precisamos de outra classe helper: FileSystems (plural novamente) que atua como um fábrica desses objetos. A seguir o trecho de código com essa estratégia:
FileSystem fileSystem = FileSystems.getDefault(); //recupera o File System
Path logo3 = fileSystem.getPath("/home/yaw/logo.png"); //cria o Path
O método resolve é util para criar um Path a partir de outro Path, respeitando a hierarquia. Veja um exemplo:
Path home = Paths.get("/home/yaw"); //diretorio home
Path logo4 = home.resolve("logo.png"); //arquivo dentro do diretorio
System.out.format("Arquivo: %s%n", logo4.toAbsolutePath());

Backup com NIO.2
Já conhecemos os componentes que representam o sistema de arquivos e o path para um arquivo ou diretório. O próximo passo é manipular os arquivos! Para isso precisamos da classe Files, uma classe helper composta por métodos que operam sobre arquivos e/ou diretórios. A seguir o trecho de código que realiza a cópia de um arquivo:
Path home = Paths.get("/home/yaw");
Path txt = home.resolve("instrucoes.txt");
Path backup = home.resolve("instrucoes.txt.backup");

//caso exista, substitui
Files.copy(txt, backup, StandardCopyOption.REPLACE_EXISTING);
System.out.format("A cópia foi criada? %s%n", Files.exists(backup));
O método copy recebe o caminho do arquivo origem e destino para reliazar a cópia. Caso o arquivo de backup já exista ele será substítuido. Agora se o arquivo de origem não existir o método lança uma IOException. Repare que para trabalhar com os métodos da classe Files, devemos tratar IOException. Seguindo no exemplo do backup, o trecho de código a seguir move o arquivo cópia para outro diretório:
Path dirDestino = Paths.get("/home/yaw/backup");
if (Files.exists(backup)) {
    Files.move(backup, dirDestino.resolve(backup.getFileName()));
}
Nos dois últimos exemplos utilizo o método exists de Files, para verificar se o arquivo realmente existe no sistema de arquivos.

Links simbólicos
A partir do Java 7 é possível criar e utilizar links simbólicos com API de I/O, através da classe Files. O próximo trecho de código demonstra como criar um link para um determinado arquivo e como verificar se o arquivo é um link.
Path alvo = Paths.get("/home/yaw/inicializacao_v1.sh");
Path link = Paths.get("/home/yaw/scripts/inicializacao.sh");

//cria o link
Files.createSymbolicLink(link, alvo);

Path f = Paths.get("/home/yaw/scripts/inicializacao.sh");

//verifica se o path eh um link
if (Files.isSymbolicLink(f)) {
  System.out.format("'%s' é link de '%s'%n", f, Files.readSymbolicLink(f));
}
Listar o conteúdo do diretório
Outra vantangem dessa API são as várias opções para consultar o conteúdo de um diretório. É possível realizar consultas simples, com filtro na extensão do arquivo, e avançadas navegando recursivamente na estrutura de diretórios.

A interface DirectoryStream nos permite iterar nos elementos contidos dentro de um diretório. A classe Files fornece várias versões do método newDirectoryStream, uma delas utilizamos a seguir indicando o filtro pela extensão jpg:

Path dir = Paths.get("/home/yaw");
String filtro = "*.jpg";

DirectoryStream<Path> stream = Files.newDirectoryStream(dir, filtro);

//iterator com os elementos da pasta
for (Path p : stream) {
  System.out.println("\t" + p);
}
Com a interface SimpleFileVisitor, que implementa o pattern Visitor, é possível criar um mecanismo mais inteligente para percorrer o conteúdo de um diretório. O método walkFileTree, da classe Files, utiliza o SimpleFileVisitor aplicado um dado diretório. Veja um exemplo dessa estratégia nessa url.

Leitura e escrita de arquivos
Outra novidade são os métodos para leitura e escrita de arquivos compactos, pequenos. Esses métodos podem ser utilizados para escrever ou ler em formato binário (bytes) ou texto (string). Veja um exemplo que lê e escreve texto:
Path txt = Paths.get("/home/yaw/instrucoes.txt");
List<String> linhas = Files.readAllLines(txt, Charset.defaultCharset());
for (String l: linhas) {
  System.out.format("%s%n",l);
}

linhas.add("novo conteudo para o arquivo texto...");
Files.write(txt, linhas, Charset.defaultCharset());
O método readAllLines retorna uma lista com todas as linhas contidas no arquivo. Repare que não foi necessário escrever código para fechar o arquivo, isso quem faz é o próprio médodo. O mesmo aconcete com o método write, logo após escrever o conteúdo ele fecha o arquivo.

Propriedades
A interface BasicFileAttributes foi criada para resgatar atributos básicos de um arquivo dentro do sistema de arquivos. Veja um exemplo de como recuperar propriedades básicas de um arquivo/diretório:
BasicFileAttributes info = Files.readAttributes(txt, BasicFileAttributes.class);

System.out.format("Data de criação: %s%n", info.creationTime());
System.out.format("Último acesso: %s%n", info.lastAccessTime());
System.out.format("Última modificação: %s%n", info.lastModifiedTime());
System.out.format("É um diretorio: %s%n", info.isDirectory());
System.out.format("Tamanho: %s bytes%n", info.size());

O código demonstrado nesse post e outros exemplos estam disponíveis no github. fique a vontade para visualizar, copiar e modificar!

O Java 7 disponibiliza outros recursos, esses links complementam o aprendizado e as novidades da linguagem:

[]s
Eder Magalhães
www.yaw.com.br
twitter.com/youandwe
twitter.com/edermag

Comentários

André Valenti disse…
Muito bom o post! E muito boa a nova API também. Gostei principalmente da nova maneira de ler linhas de e escrever linhas em arquivo. Ficou quase tão compacto quanto Python!
Yara Senger disse…
Ótimo post! Valeu!
markblog disse…
Muy buen aporte!!

Postagens mais visitadas deste blog

Melhorando Performance de JPA com Spring Web Flow

No TDC2009 realizado pela Globalcode em São Paulo foi apresentado um Lightning Talk sobre um problema específico de performance em aplicações Web com JPA e uma possível solução usando o Spring Web Flow . Num período de 15 minutos, os slides a seguir foram apresentados e seguidos de alguns vídeos de demonstração de uma aplicação Web em execução. Melhorando performance do JPA com Spring Web Flow View more presentations from Dr. Spock . Nesta apresentação foi dito que temos encontrado problemas de performance em aplicações Web que utilizam as tecnologias JSF + JPA + Ajax quando precisamos gerenciar um contexto de persistência (EntityManager). Estes problemas se manifestam quando aplicamos uma resposta errada para a pergunta: Como gerenciar o contexto de persistência numa aplicação Web? Se as aplicações não usam Ajax e limitam-se ao modelo orientado a requisições, a solução mais comum é o uso do design pattern chamado "Open Session In View Filter". Através deste design

O que é Lógica de programação?

Este é o segundo de uma série de posts voltados aos leitores do blog que estão dando início à carreira de desenvolvimento de software. O assunto de hoje é a lógica de programação. Para ler antes: Entendendo como funciona a programação de computadores: linguagens de programação, lógica, banco de dados A lógica de programação é um pré-requisito para quem quer se tornar um desenvolvedor de software, independente da linguagem de programação que se pretende utilizar. Mas o que é de fato a Lógica de Programação e como saber se eu tenho esse pré-requisito? A lógica de programação nada mais é do que a organização coerente das instruções do programa para que seu objetivo seja alcançado. Para criar essa organização, instruções simples do programa, como mudar o valor de uma variável ou desenhar uma imagem na tela do computador, são interconectadas a estruturas lógicas que guiam o fluxo da execução do programa. Isso é muito próximo ao que usamos em nosso cotidiano para realizar atividad

Dica rápida: Apagando registros duplicados no MySQL

Ola pessoal, Sei que vocês estão acostumados a ver posts meus sobre tecnologia móvel ou algo relacionado, mas hoje vou falar sobre um pequeno "truque" que usei esse final de semana com o MySQL. Eu estava desenvolvendo o lado servidor de uma nova aplicação mobile (ahh, então "tem a ver" com mobile hehe), e quando fui fazer alguns testes percebi que tinha quase 7 mil registros duplicados (!!!) na minha base de dados! Bom, o meu primeiro reflexo como programador foi pensar em fazer um "programinha" Java para buscar e deletar todos esses registros duplicados. Mas ai, resolvi tirar as teias de aranha dos neurônios e usar os vários anos de experiência que passei com SQL e criar uma query que fizesse esse trabalho todo de uma vez!! E a query ficou assim: delete from TABLE_NAME USING  TABLE_NAME, TABLE_NAME  AS  auxtable WHERE   ( NOT  TABLE_NAME.id  =  auxtable.id ) AND   ( TABLE_NAME.name  =  auxtable.name ) Explicação direta: TABLE_NAME

Muitas vagas, otimismo e sensação de reaquecimento da economia

2010 começou cedo, contrariando a expectativa que muitos Brasileiros tem de "O ano começa mesmo depois do carnaval".  Embora o inicio do ano tenha sido "repleto" de catástrofes naturais e muita chuva aqui no Brasil, no campo profissional o otimismo está evidente, as pessoas estão cheias de energia e boas perspectivas em relação as oportunidades de JavaEE 6 e muitas outras tecnologias. Mas, parece que não são somente as pessoas que estão otimistas, os anúncios de vagas voltaram a crescer, empresas anunciando boas vagas, ou grandes quantidades de vagas, refletindo o que podemos chamar de "Otimismo corporativo" . Veja algumas empresas que anunciaram vagas: IBM SpringSource   Yahoo!  Elumini   Cyberlynxx   Google Kaizen SPC Brasil Se em 2009, um ano de crise fizemos tudo isto , imagine em 2010. E você está preparado ?  Está otimista ? []s Yara http://twitter.com/yarasenger http://twitter.com/globalcode

Devo fazer um curso ou ler um livro?

Acredito que todos os instrutores ou professores, independentemente da área, escola ou centro de treinamento, já devam ter recebido essa pergunta alguma vez na vida: devo fazer um curso ou ler um livro? Para responder a essa pergunta, precisamos avaliar os prós e contras de cada opção. Trabalho com treinamento há algum tempo e, hoje, recebi essa pergunta de um aluno. Não adianta responder a ou b sem argumentar, demonstrando as opções conforme a situação do aluno. O conteúdo, a forma de transmissão e a capacidade de assimilação do indivíduo são chaves para haver benefício maior de aprendizado. Tanto em um bom curso quanto em um bom livro, o conteúdo é a premissa básica . Por conteúdo entendemos: se está organizado; se respeita pré-requisitos; se promove o aprendizado guiado e incremental; se aborda de forma satisfatória os principais pontos; se tem bom balanço entre teoria, exemplos e prática (favorecendo exemplos e prática); se tem como premissa a acessibilidade possível (e cabível) pa

JavaLi no Lançamento mundial do JDK7 em São Paulo

O Lançamento mundial do JDK7 foi realizado no dia 7/7 em três cidades simultaneamente: São Paulo (SouJava), Londres (London User Group) e São Francisco (Oracle) com transmissão ao vivo via satélite! Evidentemente as cidades não foram escolhidas por acaso, e podemos enxergar a escolha da cidade de São Paulo como um sinal de reconhecimento à comunidade Java Brasileira, ao SouJava e à Globalcode. Com certeza houveram várias pessoas fundamentais para isto, como o Bruno Souza e o Mauricio Leal responsáveis pela organização e realização do Mês de Java! Veja a entrevista com o JavaLi no TDC2011: Veja também as fotos do Lançamento do JDK7 na cobertura realizada aqui no Globalcoders. É isso aí pessoal, próxima parada ? Trilha Java TDC2011 Goiânia! E você, já se inscreveu? Participe, colabore, divulgue esta iniciativa. []s Yara Senger http://twitter.com/yarasenger