4

I am trying to convert a byte value to binary for data transfer. Basically, I am sending a value like "AC" in binary ("10101100") in a byte array where "10101100" is a single byte. I want to be able to receive this byte and convert it back into "10101100." As of now I have no success at all dont really know where to begin. Any help would be great.

edit: sorry for all the confusion I didnt realize that I forgot to add specific details.

Basically I need to use a byte array to send binary values over a socket connection. I can do that but I dont know how to convert the values and make them appear correctly. Here is an example:

I need to send the hex values ACDE48 and be able to interpret it back. According to documentation, I must convert it to binary in the following way: byte [] b={10101100,11011110,01001000}, where each place in the array can hold 2 values. I then need to convert these values back after they are sent and received. I am not sure how to go about doing this.

user1506919
  • 2,377
  • 5
  • 20
  • 15
  • 2
    What do you mean "binary"? All values are stored in binary (as they're sitting in transistors with a 1 or 0 state anyway). There's no way you really want an ASCII string of "10101100", is there?! – Jonathon Reinhart Jul 17 '12 at 18:48
  • 1
    You want a string with the value "10101100" or you want a byte variable containing that number? – Affe Jul 17 '12 at 18:49
  • 1
    Tangential question: Do you have a reason why you're hand-rolling your own binary serialisation instead of using one of the great many standard formats that come with library support? – millimoose Jul 17 '12 at 18:50
  • `"AC"` and `"10101100"` are not related at all. – Lion Jul 17 '12 at 18:50
  • @Lion I think "AC" is supposed to be a hexadecimal number. – millimoose Jul 17 '12 at 18:51
  • 1
    @Lion: In what way? 0xAC == binary 10101100. – Jon Skeet Jul 17 '12 at 18:51
  • 1
    @Lion I think you're taking the quotes too literally. `0xAC` == `0b10101100` – Bohemian Jul 17 '12 at 18:52
  • Either way - There is no reason anyone should ever have to care about the binary representation of values they're reading/writing/transmitting/receiving. (Unless you're bit-banging serially on an ouput pin of a microprocessor). – Jonathon Reinhart Jul 17 '12 at 18:52
  • To expand on Jonathon's comments. If all you want is to write the binary representation of the hexadecimal number AC to a stream, all you should need to do is `out.write((byte) 0xAC);` – millimoose Jul 17 '12 at 18:55
  • 1
    @JonathonReinhart Technically, you might want to care about the endianness of numbers larger than a byte. (Also a good reason why one would use formats that have this sort of minutiae specified.) – millimoose Jul 17 '12 at 18:56
  • @millimoose Good point. But that is still a byte-level concern, not bit-level. I feel like the OP is confused, or over-thinking his task. – Jonathon Reinhart Jul 17 '12 at 18:56
  • 1
    @Jonathon While bit level manipulation isn't common there are use cases for it. However it is a little tricky in Java because it wasn't really designed for it. – LINEMAN78 Jul 17 '12 at 19:04
  • Can you please provide an example of what the array may look like, and what you want the return value to look like? – Chris Dargis Jul 17 '12 at 19:04
  • @LINEMAN78, I understand that. Otherwise, we wouldn't have bitwise operators. My point was that when you're read/write/send/receive-ing them, you should rarely have to worry about it. **Especially** if you're in Java (not going to be touching hardware, etc.) – Jonathon Reinhart Jul 17 '12 at 19:12
  • "According to documentation, I must convert it to binary in the following way: `byte [] b={10101100,11011110,01001000}`" What is this documentation? That doesn't make sense. – Jonathon Reinhart Jul 17 '12 at 19:13
  • 1
    @Jonathon Agreed. Most of the time when I use binary or hex to string conversion it is either for debugging or input from users for data or commands that will be sent to hardware(embedded). I also agree that from the expanded question the OP is confused and my answer is not valid. – LINEMAN78 Jul 17 '12 at 19:21
  • @LINEMAN78 your answer is perfectly valid, the only thing you need to do is add support for the comma separator, that way the user can print out his byte array and copy it to source. The output rder of your function us perfect for that purpose. – Maarten Bodewes Jul 18 '12 at 07:28
  • @Jonathon I am coding an RFID tag into my program to be sent with the information and per IEEE standards for the tag, that is the correct way to send and receive the bytes of data – user1506919 Jul 18 '12 at 13:12
  • @user1506919 The question is whether the values are statically defined in hex or you need to convert them to strings for user I/O. If they never make it to the user than the only reason you should ever need to convert them to strings is for debug. – LINEMAN78 Jul 18 '12 at 16:48
  • 1
    @Jonathon Reinhart "There's no way you really want an ASCII string..." Oh, really? And there we have it ladies and gents, the most annoying kind of answer one can encounter on any Q&A site: a baseless presumption that the question itself is wrong because the commenter doesn't have his own use-case. – Chris Hatton Feb 21 '15 at 02:23
  • @ChrisHatton Actually the most annoying is the one which ressurects a nearly three year old post to badmouth someone trying to help. Rarely does one ever need to worry about the bits when dealing with communication protocols, so I was concerned that the OP was confused. – Jonathon Reinhart Feb 21 '15 at 07:51

3 Answers3

17
String toBinary( byte[] bytes )
{
    StringBuilder sb = new StringBuilder(bytes.length * Byte.SIZE);
    for( int i = 0; i < Byte.SIZE * bytes.length; i++ )
        sb.append((bytes[i / Byte.SIZE] << i % Byte.SIZE & 0x80) == 0 ? '0' : '1');
    return sb.toString();
}

byte[] fromBinary( String s )
{
    int sLen = s.length();
    byte[] toReturn = new byte[(sLen + Byte.SIZE - 1) / Byte.SIZE];
    char c;
    for( int i = 0; i < sLen; i++ )
        if( (c = s.charAt(i)) == '1' )
            toReturn[i / Byte.SIZE] = (byte) (toReturn[i / Byte.SIZE] | (0x80 >>> (i % Byte.SIZE)));
        else if ( c != '0' )
            throw new IllegalArgumentException();
    return toReturn;
}

There are some simpler ways to handle this also (assumes big endian).

Integer.parseInt(hex, 16);
Integer.parseInt(binary, 2);

and

Integer.toHexString(byte).subString((Integer.SIZE - Byte.SIZE) / 4);
Integer.toBinaryString(byte).substring(Integer.SIZE - Byte.SIZE);
LINEMAN78
  • 2,562
  • 16
  • 19
  • You should at least specify how the order of the bits in the string relate to the order of the bits in the byte array, especially as your order seems non-standard. You can actually write `fromBinary()` without if statements which should speed up your code a bit. StringBuilder can be made ready for the correct size by supplying the size in the constructor (`bytes.length * Byte.SIZE`). Finally, your fromBinary does accept invalid strings, e.g. digit of value `'2'` is translated into a zero valued bit. – Maarten Bodewes Jul 17 '12 at 19:46
  • I am confused as to why you believe that the bit order is non-standard. It is MSB first, however due to the fact that bytes are signed you will have issues with decimal representation if the MSB is set. I also added almost everything you mentioned. – LINEMAN78 Jul 17 '12 at 23:48
  • It's MSB for each byte, with the lowest index first. So you would have the lowest order byte first, with the highest order bit first. This is fine, but I would document such things carefully (but I'm a PITA regarding such details). Nice of you to make the changes! – Maarten Bodewes Jul 17 '12 at 23:58
  • I don't see where endianness comes in here. The bytes are never combined, therefore I am unclear on where you are getting that the lowest order bit is first. – LINEMAN78 Jul 18 '12 at 00:57
  • You can still order the bytes from left to right or from right to left, can't you? – Maarten Bodewes Jul 18 '12 at 07:20
  • The functions output them in the same order they were received. The order of bytes only matters when converting to integers, which is called endianness, which is supported in java.nio.ByteBuffer. The only place in my post where you would need to worry about this is if you use Integer.parseInt and allow it to parse the whole string instead of 2 and 8 characters for hex and binary strings respectively. – LINEMAN78 Jul 18 '12 at 16:46
2

For converting hexidecimal into binary, you can use BigInteger to simplify your code.

public static void sendHex(OutputStream out, String hexString) throws IOException {
    byte[] bytes = new BigInteger("0" + hexString, 16).toByteArray();
    out.write(bytes, 1, bytes.length-1);
}

public static String readHex(InputStream in, int byteCount) throws IOException {
    byte[] bytes = new byte[byteCount+1];
    bytes[0] = 1;
    new DataInputStream(in).readFully(bytes, 1, byteCount);
    return new BigInteger(0, bytes).toString().substring(1);
}

Bytes are sent as binary without translation. It fact its the only type which doesn't require some form of encoding. As such there is nothing to do.

To write a byte in binary

OutputStream out = ...
out.write(byteValue);

InputStream in = ...
int n = in.read();
if (n >= 0) {
   byte byteValue = (byte) n;
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
1

Alternative to @LINEMAN78s solution is:

public byte[] getByteByString(String byteString){
    return new BigInteger(byteString, 2).toByteArray();
}

public String getStringByByte(byte[] bytes){
    StringBuilder ret  = new StringBuilder();
    if(bytes != null){
        for (byte b : bytes) {
            ret.append(Integer.toBinaryString(b & 255 | 256).substring(1));
        }
    }
    return ret.toString();
}
lidox
  • 1,901
  • 3
  • 21
  • 40