me tirem uma dúvida, estou com um 2 métodos que fazem o seguinte processo: 1 método converte um array de bytes para um Long e o outro converte de um Long para um array de bytes, até o momento o método tem funcionado Ok, no entanto apresentou um problema na hora da conversão quando for um número negativo, ou seja, ele só funciona bem quando é número positivo, já olhei, reolhei e não consigo achar a falha, se alguém poder ajudar, dando uma luz… segue os métodos:
byteArrayToLong:
/**
* Converts from byte array to long.
* @param b - byte array
* @param size - the length
* @return
*/
public static long byteArrayToLong(byte[] b, Integer size, boolean autoLength){
int length = 0;
if (autoLength){
length = b.length;
}else{
length = size;
}
long ourLong = 0;
for (int i = 0; i < length; i++){
ourLong |= b[i] & 0xFF;
if (i+1 < length) ourLong <<= 8;
}
return ourLong;
}
longToByteArray:
/**
* Converts long in byte array with the given size.
* @param l - the long value
* @param size - the size (length) to array.
* @return a byte[].
*/
public static byte[] longToByteArray(long l, int size){
byte[] bytes = new byte[size];
int p = 0;
for (int i = size-1; i >= 0; i--){
bytes[i] = (byte) ((l >> p) & 0x0ff);
p += 8;
}
return bytes;
}
Um exemplo de execução com número positivo e saída ok:
O bit de sinal corresponderá ao bit mais significativo do seu long. Portanto, estará no 8 byte. Você está serializando apenas alguns bytes, portanto, não o bit de sinal, ele não entra na conta. 65.000 é serializado corretamente pois cabe num unsigned short (é menor que 2^16-1, que é 65535).
Lembre-se também que números negativos trabalham por complemento de 2.
O número -65.000 é representado em binário por:
1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 0000 0010 0001 1000
Se você quiser um formato mais compacto, terá que alterar a forma como armazena longs.
Aproveitei que estava revisando seus métodos e os simplifiquei. Ginásticas com bits já são suficientemente complicadas, portanto, tente deixar as operações o mais explícitas e simples possíveis:
public static long byteArrayToLong(byte[] b){
return byteArrayToLong(b, b.length);
}
/** Converts from byte array to long.
* @param b - byte array
* @param size - the length
* @return
*/
public static long byteArrayToLong(byte[] b, int size){
long ourLong = 0;
for (int i = 0; i < size; i++){
ourLong = (ourLong << 8) + (b[i] & 0xFF);
}
return ourLong;
}
public static byte[] longToByteArray(long number, int size){
byte[] bytes = new byte[size];
for (int i = 0; i < size; i++){
bytes[size-i-1] = (byte)(number & 0xFF);
number >>= 8;
}
return bytes;
}
}
Para funcionar com os negativos, use 8 no tamanho.
Também simplifiquei a assinatura das duas funções, evitando passar o null mágico. Esse estilo, com mais parâmetros e menos funções, é adotado pela MS. Eu particularmente sigo as convenções do java quando estou programando em Java (mais funções, menos parâmetros de flags).
Vini, valeuzão pela força, rodei aqui e foi, mas como vc disse eu tive que transformar o em um array de 8 bytes, no caso na aplicação que estou rodando esse valor é super variável, pode ser um array de 1,2,3…15, sendo que o tamanho que vou precisar para armazenar o long eu informo no código, na chamada do método… ai eu fiquei só com esse problema…
Eu vou agora mexer no método para ele executar como se fosse de 8 e no final tentar pegar apenas o valor que informo por parâmetro que é variável (ex. se for 2 retornar bytes[0] e bytes[1]), vou fazer aqui pra tentar, se tiver mais alguma dica quanto a isso pode passar que é bem vinda, to quebrando a cabeça desde cedo com esses bitwise/shift :O. Um forte abraço.
Deixa eu tentar entender, pra o compilador o tamanho de um Long e um Short é apenas o tamanho de memória que eles ocupam, certo? então o valor 65000 em binário seria:
0000000000000000000000000000000000000000000000000111110101101000
Mas se eu por exemplo desse o valor:
0111110101101000
poderia também dizer que são 65000? certo?
esse mesmo valor só que negativo (-65000) seria a inversão do primeiro valor onde todos os 0 viram 1 e todos os 1 viram 0 ? ficaria:
1111 1111 1111 1111 0000 0010 0001 1000 (em 4bytes)
então o valor “0000 0010 0001 1000” não já seria o negativo de 65000 em 2 bytes?
Uma forma comum de “compressão” de tipos inteiros sem sinal é a seguinte:
Coloque o byte menos significativo.
Se seu bit mais significativo for 1, passe para o próximo byte.
Repita o processo até que o bit mais significativo seja 0, ou o tamanho máximo do maior tipo numérico seja atingido.
Nesse caso, todos os dados são gravados e lidos como unsigned int (ou long, no seu caso), embora sua representação no protocolo possa ser menor de acordo com seu valor.
Para campos com sinal, pode-se usar um bit em algum lugar para representar o sinal, e o número sem sinal ser transmitido usando a compactação acima.
Ou André. Esses métodos permitem que você grave somente a quantidade necessária de bytes para representar um determinado valor numérico. Isso otimiza canais de rede, ou pode reduzir o tamanho de arquivos. É especialmente importante caso seu arquivo tenha muitos valores.