Após algumas vezes programar rotinas para capturar bytes vindos de conexão socket ou porta serial, armazenar estes bytes e em seguida processá-los para extrair a informação original, percebi logo a complexidade disso.
Qualquer um que já tenha programado um client ou server socket em Java, C++ e C ANSI sabe o que digo, pois utilizar um byte array para armazenar (bufferizar) dados recebidos antes de enquadrar uma informação significativa é uma maneira arcaica e dispensiosa.
Certo dia, resolvi simplificar esta situação com a criação de um mecanismo chamado WTByteBuffer bastante simples para prover apenas dois métodos, um método de escrita e outro de leitura a partir do ByteBuffer do Java NIO.
O método de escrita armazena os bytes lidos e o método de leitura consome os bytes. Desta forma, o programador Java será poupado de todo o trabalho discutido anteriormente para bufferizar e consumir dados recebidos.
WTByteBuffer - Classe para bufferizar
import java.nio.ByteBuffer;
public class WTByteBuffer {
public static final int DEFAULT_MAX_SIZE = 1024 * 65;
private volatile ByteBuffer buffer;
private int size;
private int bufferMaxSize;
public int getSize() {
return this.size;
}
public ByteBuffer getBuffer() {
return this.buffer;
}
public WTByteBuffer() {
this(WTByteBuffer.DEFAULT_MAX_SIZE);
}
public WTByteBuffer(int bufferMaxSize) {
this.bufferMaxSize = bufferMaxSize;
this.buffer = ByteBuffer.allocate(bufferMaxSize);
buffer.position(0);
this.size = 0;
}
public synchronized void write(byte[] bytes) {
if (this.buffer == null)
System.out.println("Buffer nulo : W");
this.buffer.put(bytes);
this.size = this.buffer.position();
}
public synchronized int read(byte[] bytes) {
int target, position, newPosition, capacity;
byte[] completeBuffer = null;
byte[] remainingBuffer = null;
if (bytes == null || bytes.length == 0) {
return 0;
}
if (this.buffer == null)
System.out.println("Buffer nulo : R");
target = bytes.length;
position = this.buffer.position();
capacity = this.buffer.capacity();
if (target > position) {
target = position;
}
newPosition = position - target;
completeBuffer = new byte[position];
remainingBuffer = new byte[newPosition];
this.buffer.flip();
this.buffer.get(completeBuffer, 0, position);
System.arraycopy(completeBuffer, 0, bytes, 0, target);
this.buffer = null;
this.buffer = ByteBuffer.allocate(capacity);
if (newPosition > 0) {
System.arraycopy(completeBuffer, target, remainingBuffer, 0, newPosition);
this.buffer.put(remainingBuffer);
}
this.size = this.buffer.position();
return target;
}
public synchronized void clear() {
if (this.buffer != null) {
this.buffer.clear();
this.buffer = null;
}
this.buffer = ByteBuffer.allocate(bufferMaxSize);
buffer.position(0);
this.size = 0;
}
}
Testando um buffer
Este exemplo cria uma instância de WTByteBuffer com 100 bytes de capacidade, escreve a série de bytes de um texto qualquer e recupera de um em um byte. Depois repete o teste recuperando de dois em dois bytes do texto bufferizado.
WTByteBuffer buffer = new WTByteBuffer(100);
String text = "ABXYZ-0123456-abc";
byte[] read = new byte[2];
byte[] serialized = text.getBytes();
int size = 0;
System.out.println("-----------------------------------------");
buffer.write(serialized);
System.out.format("Texto guardado em buffer: %s\n", text);
System.out.println("Recupera texto de 1 em 1 byte...");
while (buffer.getSize() > 0) {
read = new byte[1];
size = buffer.read(read);
System.out.format("1 byte lido: %s\n", new String(read));
}
System.out.format("Bytes guardados: %d\n", buffer.getSize());
System.out.println("-----------------------------------------");
buffer.write(serialized);
System.out.format("Texto guardado em buffer: %s\n", text);
System.out.println("Recupera texto de 2 em 2 byte...");
while (buffer.getSize() > 0) {
read = new byte[2];
size = buffer.read(read);
System.out.format("%d byte(s) lido(s): %s\n", size, new String(read));
}
buffer = null;
Numa situação real a capacidade deste buffer deverá ser maior do que 100. Caso desejar aumentar o tamanho, faça isso ao construir o WTByteBuffer ou então utilize o construtor padrão para iniciar com o tamanho padrão de reserva máxima.
A classe abordada ainda provê métodos adicionais para controle e acesso ao buffer central.
Boa sorte.
Nenhum comentário:
Postar um comentário