获得byte []数组的float []视图

时间:2018-09-05 09:48:06

标签: java arrays

我有一些二进制对象,如byte[],在对其进行一些计算之前,需要将它们转换为float[]

我当前的方法如下:

bytes[] binaryData;
float[] docVector = new float[vectorSize];
ByteBuffer.wrap(binaryData).asFloatBuffer().get(docVector);

这确实有效,但是据我了解它会创建原始数组的副本,是否有可能获得一个指向二进制数组相同内存地址的float数组?例如,在python和numpy中,可以执行以下操作以获取内存中相同数据的视图:

import numpy as np
binary_data = np.zeros(40, dtype=np.uint8)
float_array = binary_data.view(np.float32)

3 个答案:

答案 0 :(得分:2)

Java是一种繁重的面向对象语言。除了很少的原始类型之外,Java中的所有内容都是对象。

Java中的数组不能使用。与其他语言(例如C或C ++)不同,数组不是简单分配给原始类型的内存。它们是完整的完整对象,继承自java.lang.Object

通过以下示例代码,这变得显而易见:

float[] foo = new float[] {1, 2, 3, 4};
byte[] bla = new byte[] {1, 2, 3, 4};
System.out.println(foo.getClass());
System.out.println(bla.getClass());

因此,即使有一种将byte[]重新解释/转换为float[]的方法,它也会给您带来损坏的对象,因为您没有转换基础的基本类型数组,但是整个对象,并且不能保证它们的大小相同或基础数据以相同的偏移量存储。

由于Java无法获得共享相同基础二进制数据的两个不同的数组对象,因此有两种选择:

  1. 创建副本。由于某些(过时的)Java实现在调用ByteBuffer.toFloatBuffer()时会创建一个副本,因此您可能要检查是否已经创建了副本:

    float[] docVector;
    FloatBuffer floatBuffer = ByteBuffer.wrap(binaryData).asFloatBuffer();
    if (floatBuffer.hasArray()) {
        docVector = floatBuffer.array();    // Avoids copying twice
    }
    else
        docVector = new float[vectorSize];
        floatBuffer.get(docVector);
    }
    
  2. 根据您的工作,直接使用FloatBuffer而不是创建新的float[]数组就足够了。您可以以类似的方式迭代浮动对象,具体取决于您的用例和目标平台,这是内存与性能的决定。

答案 1 :(得分:2)

在Java中是不可能的。

执行类似操作的唯一方法是使用我们的Flyweight模式

编辑

我错误地使用了名称“ Flyweight”(由于@AdrianShum)。 我的意思是这样的课:

class FloatArray {
    byte[] buff;
    void set(int index, float value) { ... }
    float get(int index) { ... }
}

答案 2 :(得分:-2)

您可以将字节读取到输入流中,并从输入流中读取浮点数。

    byte [] bytesArray = new byte[120]; //array of your bytes.
    ByteInputStream bytesStream = new ByteInputStream(bytesArray, bytesArray.length);
    DataInputStream dataStream = new DataInputStream(bytesStream);
    float[] floats = new float[bytesArray.length / 4]; //float is 4 bytes. Make sure than the number of bytes can be divided by 4.
    for (int i = 0;i < floats.length; i++) {
        floats[i] = dataStream.readFloat();
    }

如果查看ByteInputStream的来源,您会发现它没有创建缓冲区的副本。

java.io.ByteInputStream

public ByteArrayInputStream(byte buf[], int offset, int length) {
    this.buf = buf;
    this.pos = offset;
    this.count = Math.min(offset + length, buf.length);
    this.mark = offset;
}

更新

将分配两个n个字节的数组。 n的一个数组是您的输入字节数组,另一个是输出float数组。如果您不想为输出数组分配内存,但是例如您需要一个个地访问这些元素,则可以创建一个索引。

class FloatIndex {

    private byte[] buffer;
    private ByteInputStream bytesStream;
    private int nFloats;
    private int count = 0;

    public FloatIndex(byte[] buffer) {
        this.buffer = buffer;
        ByteInputStream bytesStream = new ByteInputStream(buffer, buffer.length);
        if (buffer.length % 4 != 0) {
            throw new IllegalArgumentException("This buffer does not have floats");
        }
        nFloats = buffer.length / 4;
    }

    public float nextFloat() {
        DataInputStream dataStream = new DataInputStream(bytesStream);
        if (count > nFloats) {
            throw new RuntimeException("There are no more floats");
        }
        try {
            float f = dataStream.readFloat();
            count++;
            return f;
        } catch (IOException e) {
            throw new RuntimeException("Failed to read float.", e);
        }
    }

    public boolean hasNext() {
        return count > nFloats;
    }
}