I am porting some stuff from C# to Java and I need a class that can convert bytes to primitives, just like BitConverter in .NET can.
As I just posted here, I noted that my computer uses Little-Endian (Intel) and BitConverter works as expected:
// C# code
byte[] b2 = new byte[] { 0, 1 };
short b2short = BitConverter.ToInt16(b2, 0);
the b2short == 256 as expected.
Well, I needed a "BitConverter" in JAVA and found this piece of code. However, when I try it in JAVA it seems to me that the methods interpret the byte arrays as Big-Endian. JAVA-code:
// JAVA code
byte[] b2 = new byte[] { 0, 1 };
short b2short = MyFoundConverter.BitConverter.toShort(b2, 0);
In this case, b2short == 1 and that seems to me like Big-Endian.
Is the code found on this webpage interpreting the byte array as Big-Endian?
If so, is there an easy way to make it Little-Endian?
The code you linked to is taking the first byte, and making it the high-order byte of the short. The second byte goes into the low-order byte of the short. So this is a big-endian operation. The way it is coded, there would be no easy way to fix this, other than going method by method and swapping the array indexes, so that the highest index becomes the lowest.
I found another code bit that will take the data type and swap its endian-ness. Maybe you can combine the two.
The code you need is:
byte[] b2 = new byte[] { 0, 1 };
short b2short = b2[0] | (b2[1] << 8);
and for int values:
byte[] b4 = new byte[] { 0, 1, 2, 3 };
int b4int = b4[0] | (b4[1] << 8) | (b4[2] << 16) | (b4[3] << 24);
you get the idea :-)
Related
I need to convert integers that I send over 4bytes per socket in java. The problem is that when the integer exceeds 9, ie [10, +inf] my crash code.
I read in the instructions this line:
All multi-byte integer values are encoded using the two's compliment notation in the big-endian order.
The problem is that I don't know how to write the appropriate conversion function. Here is the one I had implemented and which seems to work for integers from 0 to 9. Can someone help me.
byte[] size_buffer = new byte[4];
for (int i = 0; i < 4; i++) {
size_buffer[i] = (byte)(msg_size >>> (i * 8));
}
ByteBuffer has nice functionality for this:
byte[] bytes = new byte[4];
ByteBuffer.wrap(bytes)
.order(ByteOrder.BIG_ENDIAN) // make explicit
.putInt(intValue);
// bytes is now updated
ByteBuffer Doc in java SE 8
I need to convert integers that I send over 4bytes per socket in java.
Probably no actual conversion is required.
The problem is that when the integer exceeds 9, ie [10, +inf] my crash code.
Nothing in what you have presented suggests why that would be, though in fact the conversion presented is wrong.
All multi-byte integer values are encoded using the two's compliment notation in the big-endian order.
This is Java's native representation for type int. You can write ints to the socket's output stream by wrapping it in a DataOutputStream and using DataOutputStream.writeInt(). Or if you are using NIO then you can put an int into a ByteBuffer via the buffer's putInt() method. Either of these approaches sidesteps any need to manually encode integers into byte arrays.
But if you insist on doing your own conversion, completely manually, then this ...
byte[] size_buffer = new byte[4];
for (int i = 0; i < 4; i++) {
size_buffer[i] = (byte)(msg_size >>> (i * 8));
}
... reads out the bytes in little-endian order instead of big-endian (most-significant to least). This would be a correct alternative:
byte[] size_buffer = new byte[4];
for (int i = 0; i < 4; i++) {
size_buffer[i] = (byte)(msg_size >>> ((3 - i) * 8));
}
You state you tried +Inf, but that is not an int value. The only number type you can stick +Inf into is double or float, but it's a compiler error to attempt to do >>> to a double or float.
Also, the code snippet you wrote doesn't work for anything - it turns things into little endian order. It treats 9 the exact same way it treats 10: 9 turns into [9, 0, 0, 0] (which is 9 in 2's complement int, but, little endian), and 10 becomes [10, 0, 0, 0].
In other words, you've either thoroughly misanalysed your own code, or you aren't running that snippet.
This will work fine:
int n = -2;
byte[] sizeBuffer = new byte[4];
for (int i = 0; i < 4; i++) {
sizeBuffer[i] = (byte)(n >>> (24 - (i * 8)));
}
Turns -1 into [255, 255, 255, 254] (in java bytes are rendered signed, so if you try to print that, it'll probably show as -1, -1, -1, -2. It's the same thing) - and that is indeed -2 in 2's complement big endian.
You can make a ByteBuffer and write that way as well.
I have doubt in Type casting in java. In type casting we can convert long type value into Byte. What is the purpose of converting long to byte in java, if there is any Real time Example for this. eg:
long l=1000;
byte b=(byte)l;
System.out.println(b);
The output is -24. Here 1000 is converted into -24, where this conversion used in real projects.
Well imagine you have an object lets say a Color, that is an integer (32 bits wide) that object is holding a RGBA information, now you need to get only the 1st byte because only the alpha part is relevant to you...
int myColor = 999;
byte alpha = (byte)myColor;
now alpha is -25, the fact that 999 is now turned into -25 is not relevant at all, the point is that that cast is actually masking and truncating the not relevant information,
999 = 0000_0011_1110_0111
-25 = 1110_0111
Here is a real world example:
public byte[] longToBytes(long l) {
byte[] bytes = new byte[8];
bytes[0] = (byte)(l >> 56);
bytes[1] = (byte)(l >> 48);
// ...
bytes[7] = (byte)(l);
return bytes;
}
The purpose of this code is self-evident ... and it won't compile without the typecast.
I have this 40 bit key in a byteArray of size 8, and I want to add 0 padding to it until it becomes 56 bit.
byte[] aKey = new byte [8]; // How I instantiated my byte array
Any ideas how?
An 8 byte array is of 64 bits. If you initialize the array as
byte[] aKey = new byte [8]
all bytes are initialized with 0's. If you set the first 40 bits, that is 5 bytes, then your other 3 bytes, i.e, from 41 to 64 bits are still set to 0. So, you have by default from 41st bit to 56th bit set to 0 and you don't have to reset them.
However, if your array is already initialized with some values and you want to clear the bits from 41 to 56, there are a few ways to do that.
First:
you can just set aKey[5] = 0 and aKey[6] = 0 This will set the 6th bye and the 7th byte, which make up from 41st to 56th bit, to 0
Second: If you are dealing with bits, you can also use BitSet. However, in your case, I see first approach much easier, especially, if you are pre Java 7, some of the below methods do not exist and you have to write your own methods to convert from byte array to bit set and vice-versa.
byte[] b = new byte[8];
BitSet bitSet = BitSet.valueOf(b);
bitSet.clear(41, 56); //This will clear 41st to 56th Bit
b = bitSet.toByteArray();
Note: BitSet.valueOf(byte[]) and BitSet.toByteArray() exists only from Java 7.
Use System.arraycopy() to insert two bytes (56-40 = 16 bit) at the start of your array.
static final int PADDING_SIZE = 2;
public static void main(String[] args) {
byte[] aKey = {1, 2, 3, 4, 5, 6, 7, 8}; // your array of size 8
System.out.println(Arrays.toString(aKey));
byte[] newKey = new byte[8];
System.arraycopy(aKey, 0, newKey, PADDING_SIZE, aKey.length - PADDING_SIZE); // right shift
System.out.println(Arrays.toString(newKey));
}
Guava's com.google.common.primitives.Bytes.ensureCapacity:
aKey = Bytes.ensureCapacity(aKey , 56/8, 0);
or since JDK6 using Java native tools:
aKey = java.util.Arrays.copyOf(aKey , 56/8);
i was wondering if the solution for this documented here is still the solution or is there any other way getting an int from 4 bytes?
thank you.
EDIT: im getting the byte[] from sockets .read
EDIT: int recvMsgSize = in.read(Data, 0, BufferSize); if recvMsgSize is -1 i know the connection has been dropped.
how do i detect this when im using DataInputStream instead of InputStream?
thanks.
EDIT: apologies for being a yoyo regarding accepting the right answer. but after mihi's updated final response, it would appear that the method is solid and cuts down extended coding and in my opinion best practice.
You have to be very careful with any widening conversion and numeric promotion, but the code below converts 4 byte into int:
byte b1 = -1;
byte b2 = -2;
byte b3 = -3;
byte b4 = -4;
int i = ((0xFF & b1) << 24) | ((0xFF & b2) << 16) |
((0xFF & b3) << 8) | (0xFF & b4);
System.out.println(Integer.toHexString(i)); // prints "fffefdfc"
See also
Java code To convert byte to Hexadecimal
Pay attention to the need to mask with & 0xFF -- you'll probably end up doing a lot of this if you're working with byte since all arithmetic operations promote to int (or long)
If you have them already in a byte[] array, you can use:
int result = ByteBuffer.wrap(bytes).getInt();
or, if you have Google's guava-libraries on your classpath, you have the shortcut:
int result = Ints.fromByteArray(array);
which has the advantage that you have similarly nice APIs for other types (Longs.fromByteArray, Shorts.fromByteArray, etc).
Depending on where you get those 4 bytes from:
http://docs.oracle.com/javase/7/docs/api/java/io/DataInput.html#readInt()
http://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html#getInt(int)
You can of course still do it manually, but in most cases using one of those (if you have to convert a byte array with lots of bytes, you might want to use a DataInputStream around a ByteArrayInputStream for example) is easier.
Edit: If you need to change the endianness, you will have to use a ByteBuffer, or reverse the bytes yourself, or do the conversion yourself, as DataInput does not support changing the endianness.
Edit2: When you get them from the socket input stream, I'd wrap that one into a DataInputStream and use it for reading all kinds of data. Especially since InputStream.read(byte[]) will not guarantee to fill the whole byte array... DataInputStream.readFully does.
DataInputStream in = new DataInputStream(socket.getInputStream());
byte aByte = in.readByte();
int anInt = in.readInt();
int anotherInt = in.readInt();
short andAShort = in.readShort(); // 11 bytes read :-)
byte[] lotOfBytes = new byte[anInt];
in.readFully(lotOfBytes);
Edit3: When reading multiple times from a stream, they will continue reading where you stopped, i. e. aByte will be byte 0, anInt will be bytes 1 to 4, anotherInt will be bytes 5 to 8, etc. readFully will read on after all that and will block until it has read lotOfbytes.
When the stream stops (the connection drops) you will get EOFException instead of -1, so if you get -1, the int really was -1.
If you do not want to parse any bytes at all, you can skip() them. Parsing one byte in 2 different ways is not possible with DataInputStream (i. e. read first an int from byte 0 to 3, then one from byte 2 to 5), but usually not needed either.
Example:
// read messages (length + data) until the stream ends:
while (true) {
int messageLength;
try {
messageLength = in.readInt(); // bytes 0 to 3
} catch (EOFException ex) {
// connection dropped, so handle it, for example
return;
}
byte[] message = new byte[messageLength];
in.readFully(message);
// do something with the message.
}
// all messages handled.
Hope this answers your additional questions.
A solution in functional style (just for variety, imho not very convinient in use):
private int addByte (int base, byte appendix) {
return (base << 4) + appendix;
}
public void test() {
byte b1 = 5, b2 = 5, byte b3 = 0, b4 = 1;
int result = addByte (addByte (addByte (addByte (0, b1), b2), b3), b4);
}
As mihi said, it depends on where you are getting those bytes from, but this code might be of use:
int myNumber = (((int)byteOne) << 0) |
(((int)byteTwo) << 8) |
(((int)byteThree) << 16) |
(((int)byteFour) << 24);
I'm working with java.
I have a byte array (8 bits in each position of the array) and what I need to do is to put together 2 of the values of the array and get a value.
I'll try to explain myself better; I'm extracting audio data from a audio file. This data is stored in a byte array. Each audio sample has a size of 16 bits. If the array is:
byte[] audioData;
What I need is to get 1 value from samples audioData[0] and audioData[1] in order to get 1 audio sample.
Can anyone explain me how to do this?
Thanks in advance.
I'm not a Java developer so this could be completely off-base, but have you considered using a ByteBuffer?
Assume the LSB is at data[0]
int val;
val = (((int)data[0]) & 0x00FF) | ((int)data[1]<<8);
As suggested before, Java has classes to help you with this. You can wrap your array with a ByteBuffer and then get an IntBuffer view of it.
ByteBuffer bb = ByteBuffer.wrap(audioData);
// optional: bb.order(ByteOrder.BIG_ENDIAN) or bb.order(ByteOrder.LITTLE_ENDIAN)
IntBuffer ib = bb.asIntBuffer();
int firstInt = ib.get(0);
ByteInputStream b = new ByteInputStream(audioData);
DataInputStream data = new DataInputStream(b);
short value = data.readShort();
The advantage of the above code is that you can keep reading the rest of 'data' in the same way.
A simpler solution for just two values might be:
short value = (short) ((audioData[0]<<8) | (audioData[1] & 0xff));
This simple solution extracts two bytes, and pieces them together with the first byte being the higher order bits and the second byte the lower order bits (this is known as Big-Endian; if your byte array contained Little-Endian data, you would shift the second byte over instead for 16-bit numbers; for Little-Endian 32-bit numbers, you would have to reverse the order of all 4 bytes, because Java's integers follow Big-Endian ordering).
easier way in Java to parse an array of bytes to bits is JBBP usage
class Parsed { #Bin(type = BinType.BIT_ARRAY) byte [] bits;}
final Parsed parsed = JBBPParser.prepare("bit:1 [_] bits;").parse(theByteArray).mapTo(Parsed.class);
the code will place parsed bits of each byte as 8 bytes in the bits array of the Parsed class instance
You can convert to a short (2 bytes) by logical or-ing the two bytes together:
short value = ((short) audioData[0]) | ((short) audioData[1] << 8);
I suggest you take a look at Preon. In Preon, you would be able to say something like this:
class Sample {
#BoundNumber(size="16") // Size of the sample in bits
int value;
}
class AudioFile {
#BoundList(size="...") // Number of samples
Sample[] samples;
}
byte[] buffer = ...;
Codec<AudioFile> codec = Codecs.create(AudioFile.class);
AudioFile audioFile = codec.decode(buffer);
You can do it like this, no libraries or external classes.
byte myByte = (byte) -128;
for(int i = 0 ; i < 8 ; i++) {
boolean val = (myByte & 256) > 0;
myByte = (byte) (myByte << 1);
System.out.print(val ? 1 : 0);
}
System.out.println();
byte myByte = 0x5B;
boolean bits = new boolean[8];
for(int i = 0 ; i < 8 ; i++)
bit[i] = (myByte%2 == 1);
The results is an array of zeros and ones where 1=TRUE and 0=FALSE :)