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.
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:
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:
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 PathO 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:
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:
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
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:
- Type Inference no Java 7, generics com código compacto;
- O novo try no Java 7 por uma linguagem mais simples;
- Lançamento do JDK 7 no TDC2011 em São Paulo;
- Artigo no InfoQ Brasil - Java 7: Modificações na Linguagem, em detalhes e exemplos;
- Minicurso Gratuito: JDK7 - Modificações na Linguagem;
- Tutorial da Oracle sobre NIO.2;
[]s
Eder Magalhães
www.yaw.com.br
twitter.com/youandwe
twitter.com/edermag
Comentários