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
int
comowriteInt(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.bin
gerado 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
DataOutputStream
escreve tipos primitivos do Java em um formato binário, compacto e portátil.DataInputStream
lê 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.