11

So what I'm trying to do here is get a float[], convert it to byte[], send it through the network as a datagram packet and then convert it back to a byte[] at the receiving terminal.

Now I know I can convert float[] to byte[] by using the getBytes[] method. But I don't know how to reverse the conversion.

mskfisher
  • 3,291
  • 4
  • 35
  • 48
brain56
  • 2,659
  • 9
  • 38
  • 70

9 Answers9

12

I think you want to make use of the ByteBuffer class, which has putFloat and getFloat methods.

Dawood ibn Kareem
  • 77,785
  • 15
  • 98
  • 110
  • Thanks! I think this is it. I'll give it a go when I get the time and I'll let you know what happens. – brain56 Feb 19 '12 at 04:49
  • 1
    @brain56: just wanted to add that if you're sending this over a network, you would want to explicitly specify an encoding instead of leaving yourself at the mercy of the platform's default encoding. – Lie Ryan Feb 19 '12 at 05:09
  • 1
    ByteBuffer also has the asFloatBuffer() method in case you do not want to extract the values individually you can chain the method calls: ByteBuffer.wrap(someByteArray).asFloatBuffer().array() to go from a byte[] to a float[] – Steven Magana-Zook Aug 08 '14 at 18:51
  • @StevenMagana-Zook You could post that as an answer. – Dawood ibn Kareem Aug 08 '14 at 19:33
6

Another way... use ByteArrayOutputStream/DataOutputStream for output

float fArr[] = ...;
ByteArrayOutputStream bas = new ByteArrayOutputStream();
DataOutputStream ds = new DataOutputStream(bas);
for (float f : fArr) 
    ds.writeFloat(f);
byte[] bytes = bas.toByteArray();

Use ByteArrayInputStream/DataInputStream for input

byte[] buffer = ...;
ByteArrayInputStream bas = new ByteArrayInputStream(buffer);
DataInputStream ds = new DataInputStream(bas);
float[] fArr = new float[buffer.length / 4];  // 4 bytes per float
for (int i = 0; i < fArr.length; i++)
{
    fArr[i] = ds.readFloat();
}
ricosrealm
  • 1,616
  • 1
  • 16
  • 26
3

This is more for my future reference than anything else.

public static byte[] floatToByte(float[] input) {
    byte[] ret = new byte[input.length*4];
    for (int x = 0; x < input.length; x++) {
        ByteBuffer.wrap(ret, x*4, 4).putFloat(input[x]);
    }
    return ret;
}

public static float[] byteToFloat(byte[] input) {
    float[] ret = new float[input.length/4];
    for (int x = 0; x < input.length; x+=4) {
        ret[x/4] = ByteBuffer.wrap(input, x, 4).getFloat();
    }
    return ret;
}

Can be reduced to a single line like https://stackoverflow.com/a/44104399/322017.

Nicolas
  • 1,106
  • 11
  • 25
3

Use Float.floatToIntBits() to extract the bit-value of the float as an integer, then use BigInteger.toByteArray() to make a byte[]. This can be reversed using the BigInteger constructor that takes a byte[] argument, and then Float.intBitsToFloat().

Jim Garrison
  • 85,615
  • 20
  • 155
  • 190
2

An improvement to Steven Chou's answer

final static int BYTES_IN_FLOAT = Float.SIZE / Byte.SIZE;

public static byte[] toByteArray(float[] floatArray) {
    ByteBuffer buffer = ByteBuffer.allocate(floatArray.length * BYTES_IN_FLOAT)
    buffer.asFloatBuffer().put(floatArray);
    return buffer.array();
}


public static float[] toFloatArray(byte[] byteArray) {
    float[] result = new float[byteArray.length / BYTES_IN_FLOAT];
    ByteBuffer.wrap(byteArray).asFloatBuffer().get(result, 0, result.length);
    return result;
}
Gk Mohammad Emon
  • 6,084
  • 3
  • 42
  • 42
MA90
  • 23
  • 3
1

Sender:

ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
// byteBuffer reused for every element in floatArray
ByteBuffer byteBuffer = ByteBuffer.allocate(4);
// go through the elements in the float array writing its
// byte equivalent  to the stream
for(float element : floatArray) {
  byteBuffer.clear();
  byteBuffer.putFloat(element)
  byteStream.write(byteBuffer.array());
}

// Logic for sending bytestream's bytes as datagram packet
// can get byte[] from steam by: byteStream.toByteArray();

Receiver:

ArrayList<Float> receivedValues = new ArrayList<Float>();
ByteBuffer byteBuffer = ByteBuffer.wrap(receivedBytes);

// while there is still 4 bytes left on the byte buffer
// grab the next float and add it to the received list
int position = 0;
while(byteBuffer.capactiy - position >= 4) {
  receivedValues.add(byteBuffer.getFloat(position));
  position += 4;
}

float[] result = new float[receivedValues.count];
return receivedValues.toArray(new float[receivedValues.size()]);
Antoine Dahan
  • 574
  • 2
  • 9
  • 23
0

You need to use the getFloat() and putFloat() commands in the FloatBuffer of the ByteBuffer. In fact, you should certainly do this simply because of the sheer speed. And it's a great thing to understand for byte manipulations. You can also mix and match the data, and put and get it as needed. All of it is backed by the byte buffer. So the common happening of sending an array, you need to send the size of the array too.

public static void writeFloatArray(float[] array, OutputStream stream) throws IOException {
    ByteBuffer buffer = ByteBuffer.allocate(4 * (array.length + 1)).putInt(array.length);
    buffer.asFloatBuffer().put(array,0,array.length);
    stream.write(buffer.array());
}

You just make sure to allocate enough bytes to store everything in the buffer. Write some stuff, write some other stuff etc. Understanding this point makes things way easier. On the flipside we do basically the same thing, though we require an additional read because we don't know how big the array is, just that there is one:

public static float[] readFloatArray(InputStream in) throws IOException {
    byte[] data = new byte[4];
    if (readFully(in, data) != data.length) return null;
    int length = ByteBuffer.wrap(data).getInt();
    data = new byte[length * 4];
    if (readFully(in,data) != data.length) return null;
    float[] array = new float[length];
    ByteBuffer.wrap(data).asFloatBuffer().get(array,0,array.length);
    return array;
}

And for full functionality, though not exactly part of this:

public static int readFully(InputStream in, byte[] data) throws IOException {
    int offset = 0;
    int bytesRead;
    boolean read = false;
    while ((bytesRead = in.read(data, offset, data.length - offset)) != -1) {
        read = true;
        offset += bytesRead;
        if (offset >= data.length) {
            break;
        }
    }
    return (read) ? offset : -1;
}
Tatarize
  • 10,238
  • 4
  • 58
  • 64
0

ByteBuffer document: https://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html

final static int nbBytesInFloat = Float.SIZE / Byte.SIZE;

public static byte[] toByteArray(float[] floatArray){
    byte[] result = new byte[floatArray.length * nbBytesInFloat];
    ByteBuffer wrappedBytes = ByteBuffer.wrap(result);
    for(int i=0;i<floatArray.length;i++) {
        wrappedBytes.putFloat(floatArray[i]);
    }
    return result;
}


public static float[] toFloatArray(byte[] byteArray){
    ByteBuffer buffer = ByteBuffer.wrap(byteArray);

    float[] result = new float[byteArray.length / nbBytesInFloat];
    for(int i=0;i<result.length;i++) {
        result[i] = buffer.getFloat();
    }
    return result;
}

If your application is more performance sensitive, then you can consider this solution without creating many objects:

public byte[] floatArrayToByteArray(float[] floatArray) {
    byte[] byteArray = new byte[floatArray.length * 4];
    int byteArrayIndex = 0;
    for (int i = 0; i < floatArray.length; i++) {
        int rawInt = Float.floatToRawIntBits(floatArray[i]);
        byteArray[byteArrayIndex] = (byte) (rawInt >>> 24);
        byteArray[byteArrayIndex + 1] = (byte) (rawInt >>> 16);
        byteArray[byteArrayIndex + 2] = (byte) (rawInt >>> 8);
        byteArray[byteArrayIndex + 3] = (byte) (rawInt);
        byteArrayIndex += 4;
    }
    return byteArray;
}
Steven Chou
  • 1,504
  • 2
  • 21
  • 43
-4

Byte class has a method floatValue();

http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Byte.html#floatValue%28%29

sriram
  • 378
  • 1
  • 7
  • 21
  • 2
    But that won't give you general float values, only those that represent whole numbers between 0 and 255. A float needs 4 bytes, and the floatValue method of the Byte class only works with one. – Dawood ibn Kareem Feb 19 '12 at 04:44