Streams e NIO
Esta lição aborda IO baseado em fluxos do Java e NIO para operações com arquivos de baixo nível.
Arquitetura de IO Streams
Fluxos de Entrada (Leitura)
InputStream (entrada de bytes)
├── FileInputStream (arquivo)
├── BufferedInputStream (buffer)
├── ByteArrayInputStream (array de bytes)
└── DataInputStream (tipos primitivos)
Reader (entrada de caracteres)
├── FileReader (arquivo)
├── BufferedReader (buffer)
└── InputStreamReader (conversão)
Fluxos de Saída (Escrita)
OutputStream (saída de bytes)
├── FileOutputStream (arquivo)
├── BufferedOutputStream (buffer)
└── DataOutputStream (tipos primitivos)
Writer (saída de caracteres)
├── FileWriter (arquivo)
├── BufferedWriter (buffer)
└── OutputStreamWriter (conversão)
Fluxos de Bytes
FileInputStream Leitura
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputStreamDemo {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("test.txt")) {
int data;
while ((data = fis.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
FileOutputStream Escrita
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamDemo {
public static void main(String[] args) {
try (FileOutputStream fos = new FileOutputStream("output.txt")) {
String text = "Olá, Mundo!";
fos.write(text.getBytes());
System.out.println("Escrita bem-sucedida");
} catch (IOException e) {
e.printStackTrace();
}
}
}
Exemplo: Cópia de Arquivo com Fluxo de Bytes
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteCopy {
public static void copy(String src, String dest) throws IOException {
try (FileInputStream fis = new FileInputStream(src);
FileOutputStream fos = new FileOutputStream(dest)) {
byte[] buffer = new byte[1024];
int length;
while ((length = fis.read(buffer)) != -1) {
fos.write(buffer, 0, length);
}
}
}
public static void main(String[] args) {
try {
copy("source.txt", "dest.txt");
System.out.println("Cópia concluída");
} catch (IOException e) {
e.printStackTrace();
}
}
}
Fluxos com Buffer
Fluxos com buffer melhoram a eficiência do IO reduzindo a frequência de acessos ao disco.
BufferedInputStream/BufferedOutputStream
import java.io.*;
public class BufferedStreamDemo {
public static void main(String[] args) throws IOException {
// Escrever
try (BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("buffered.txt"))) {
for (int i = 0; i < 1000; i++) {
bos.write(("Linha " + i + "\n").getBytes());
}
}
// Ler
try (BufferedInputStream bis = new BufferedInputStream(
new FileInputStream("buffered.txt"))) {
byte[] buffer = new byte[1024];
int length;
while ((length = bis.read(buffer)) != -1) {
System.out.write(buffer, 0, length);
}
}
}
}
Fluxos de Dados
DataInputStream/DataOutputStream podem ler e escrever tipos primitivos.
Exemplo: Fluxos de Dados
import java.io.*;
public class DataStreamDemo {
public static void main(String[] args) throws IOException {
// Escrever
try (DataOutputStream dos = new DataOutputStream(
new FileOutputStream("data.dat"))) {
dos.writeInt(100);
dos.writeDouble(3.14);
dos.writeUTF("Olá");
}
// Ler
try (DataInputStream dis = new DataInputStream(
new FileInputStream("data.dat"))) {
int i = dis.readInt();
double d = dis.readDouble();
String s = dis.readUTF();
System.out.println("int: " + i); // 100
System.out.println("double: " + d); // 3.14
System.out.println("string: " + s); // Olá
}
}
}
NIO (New IO)
Java NIO fornece operações de IO mais eficientes.
Interface Path
import java.nio.file.Path;
import java.nio.file.Paths;
public class PathDemo {
public static void main(String[] args) {
Path path = Paths.get("/home/user/test.txt");
System.out.println("Nome do arquivo: " + path.getFileName()); // test.txt
System.out.println("Pai: " + path.getParent()); // /home/user
System.out.println("Raiz: " + path.getRoot()); // /
System.out.println("Contagem de nomes: " + path.getNameCount()); // 3
}
}
Classe Utilitária Files
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
public class FilesDemo {
public static void main(String[] args) throws IOException {
Path path = Paths.get("test.txt");
// Verificar
System.out.println("Existe: " + Files.exists(path));
System.out.println("É arquivo: " + Files.isRegularFile(path));
System.out.println("É legível: " + Files.isReadable(path));
// Ler todas as linhas
List<String> lines = Files.readAllLines(path);
lines.forEach(System.out::println);
// Ler como array de bytes
byte[] bytes = Files.readAllBytes(path);
System.out.println("Tamanho: " + bytes.length);
// Escrever
Files.write(Paths.get("output.txt"), "Olá".getBytes());
// Criar diretório
Files.createDirectories(Paths.get("newdir/subdir"));
// Copiar
Files.copy(Paths.get("source.txt"), Paths.get("dest.txt"));
// Mover
Files.move(Paths.get("old.txt"), Paths.get("new.txt"));
// Deletar
Files.deleteIfExists(Paths.get("temp.txt"));
}
}
Atributos de Arquivo
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
public class FileAttributes {
public static void main(String[] args) throws IOException {
Path path = Paths.get("test.txt");
BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
System.out.println("Tamanho: " + attrs.size());
System.out.println("Criado: " + attrs.creationTime());
System.out.println("Modificado: " + attrs.lastModifiedTime());
System.out.println("É diretório: " + attrs.isDirectory());
System.out.println("É arquivo: " + attrs.isRegularFile());
}
}
Percorrer Arquivos (NIO)
import java.io.IOException;
import java.nio.file.*;
import java.util.stream.Stream;
public class NIODirectoryWalk {
public static void main(String[] args) throws IOException {
Path dir = Paths.get(".");
// Listar diretório
try (Stream<Path> stream = Files.list(dir)) {
stream.forEach(path -> {
String type = Files.isDirectory(path) ? "[DIR]" : "[ARQ]";
System.out.println(type + " " + path.getFileName());
});
}
// Percorrer recursivamente
try (Stream<Path> stream = Files.walk(dir, 3)) { // Máximo 3 níveis
stream.forEach(path -> System.out.println(path));
}
// Encontrar arquivos
try (Stream<Path> stream = Files.find(dir, 10,
(path, attrs) -> attrs.isRegularFile() && path.toString().endsWith(".txt"))) {
stream.forEach(System.out::println);
}
}
}
IO vs NIO
| Recurso | IO | NIO |
|---|---|---|
| Modelo | Orientado a fluxo | Orientado a buffer |
| Bloqueio | IO bloqueante | IO não bloqueante |
| Seletores | Nenhum | Sim |
| API | Mais antiga | Mais nova |
Guia de Seleção
| Cenário | Recomendação |
|---|---|
| Leitura/escrita simples de arquivos | Classe utilitária Files |
| Processamento de arquivos grandes | Fluxos com buffer |
| Rede de alta concorrência | NIO |
| Manutenção de código legado | Fluxos IO |
❓ Perguntas Frequentes
P: Como escolher entre fluxos de bytes e fluxos de caracteres? R: Use fluxos de caracteres para arquivos de texto, fluxos de bytes para arquivos binários.
P: Quais são os benefícios dos fluxos com buffer? R: Reduzem a frequência de acessos ao disco, melhorando a eficiência do IO.
P: NIO é mais rápido que IO? R: Não necessariamente. As principais vantagens do NIO são não bloqueio e seletores. Para operações simples com arquivos, a diferença é mínima.
📖 Resumo
- Fluxos IO são divididos em fluxos de bytes e fluxos de caracteres
- Fluxos com buffer melhoram a eficiência do IO
- NIO fornece operações com arquivos mais eficientes
- Classe utilitária Files simplifica operações com arquivos
📝 Exercícios
- Comparação de arquivos: Compare dois arquivos para verificar se são idênticos
- Processamento de arquivos grandes: Leia arquivos grandes em pedaços, conte linhas
- Sincronização de diretórios: Sincronize um diretório para outro
Próxima Lição
Na próxima lição, aprenderemos sobre Regex e JSON — técnicas avançadas de processamento de strings.



