Streams de Dados Primitivos em Java: DataOutputStream e DataInputStream
Para gravar e ler tipos de dados primitivos do Java (int, double, boolean, etc.) em um formato binário e independente de plataforma, são utilizadas as classes DataOutputStream e DataInputStream. Elas são ideais para situações onde é necessário um formato de arquivo compacto, rápido e bem definido, garantindo que os dados possam ser lidos corretamente em qualquer sistema.
Escrita de Dados com DataOutputStream
A classe DataOutputStream é um "decorator" que envolve um OutputStream existente e adiciona a capacidade de escrever tipos de dados primitivos em formato binário. Para cada tipo, existe um método de escrita correspondente:
writeBoolean(boolean v): grava um valor booleano (1 byte).writeByte(int v): grava um byte.writeChar(int v): grava umchar(2 bytes).writeDouble(double v): grava umdouble(8 bytes).writeFloat(float v): grava umfloat(4 bytes).writeInt(int v): grava umint(4 bytes).writeLong(long v): grava umlong(8 bytes).writeShort(int v): grava umshort(2 bytes).writeUTF(String str): grava uma string em formato UTF-8 modificado.
Leitura de Dados com DataInputStream
De forma complementar, a DataInputStream envolve um InputStream para ler dados primitivos de um stream binário. Para cada método de escrita, há um método de leitura correspondente:
boolean readBoolean()byte readByte()char readChar()double readDouble()float readFloat()int readInt()long readLong()short readShort()String readUTF()
Exemplo Prático: Serializando Dados de um Objeto
O exemplo a seguir demonstra como gravar os dados de um objeto Person em um arquivo binário e, em seguida, lê-los de volta.
import java.io.*;
class Person {
public String name;
public int age;
public double height;
public boolean married;
public Person(String n, int a, double h, boolean m) {
this.name = n;
this.age = a;
this.height = h;
this.married = m;
}
}
public class Program {
public static void main(String[] args) {
Person tom = new Person("Tom", 34, 1.68, false);
// Bloco de escrita no arquivo
try (DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.bin"))) {
// Gravando os valores dos campos do objeto
dos.writeUTF(tom.name);
dos.writeInt(tom.age);
dos.writeDouble(tom.height);
dos.writeBoolean(tom.married);
System.out.println("File has been written");
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
// Bloco de leitura do arquivo
try (DataInputStream dis = new DataInputStream(new FileInputStream("data.bin"))) {
// Lendo os valores na mesma ordem em que foram escritos
String name = dis.readUTF();
int age = dis.readInt();
double height = dis.readDouble();
boolean married = dis.readBoolean();
System.out.printf("Name: %s Age: %d Height: %.2f Married: %b",
name, age, height, married);
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
}Atenção à Ordem e Tipos de Dados
O ponto mais crítico ao usar DataInputStream e DataOutputStream é que os dados devem ser lidos exatamente na mesma ordem e com os mesmos tipos em que foram escritos.
No exemplo acima, a ordem de escrita foi String, int, double, boolean. A leitura segue essa mesma sequência. Tentar ler os dados em uma ordem diferente (ex: readInt() primeiro) ou com tipos incompatíveis (ex: readInt() onde um double foi escrito) resultará em dados corrompidos ou no lançamento de uma exceção, como EOFException (se a leitura tentar ultrapassar o final do arquivo).
Por que usar Data Streams?
- Formato Compacto: Gravar um
intcomowriteInt(123456789)ocupa apenas 4 bytes. Gravar o mesmo número como texto em um arquivo ("123456789") ocuparia 9 bytes. Para grandes volumes de dados, a economia de espaço é significativa. - Performance: Ler e escrever dados binários é muito mais rápido do que converter texto para números (parsing) e vice versa.
- Independência de Plataforma: O formato binário usado por essas classes é padronizado pela JVM. Um arquivo
data.bingerado em um sistema Windows pode ser lido corretamente em um sistema Linux ou macOS, sem preocupações com a representação de bytes (endianness) do sistema operacional.
Resumo
DataOutputStreamescreve tipos primitivos do Java em um formato binário, compacto e portátil.DataInputStreamlê tipos primitivos desse mesmo formato.- Essa abordagem é útil para criar arquivos de dados de alto desempenho ou para comunicação em rede.
- A regra fundamental é que a ordem e os tipos dos dados na leitura devem corresponder perfeitamente à ordem e aos tipos na escrita.