使用Java中的流将double []转换为byte []

时间:2022-03-30 19:03:02

Hey I'm working on an app that uses Paho mqtt

嘿,我正在开发一个使用Paho mqtt的应用程序

Now I'm trying to cast the contents of a couple of objects to byte arrays so I can send them to the broker. There are a couple of different objects that all adhere to a abstract class, but the one I started with contains a double[]

现在我正在尝试将几个对象的内容转换为字节数组,以便将它们发送给代理。有几个不同的对象都遵循抽象类,但我开始使用的是一个double []

Here's the function I'm trying to implement:

这是我正在尝试实现的功能:

    @Override
public byte[] getBytes() {

    return Arrays.stream(driveVector).map(d -> Double.valueOf(d).byteValue()).toArray();
}

I thought this would work, but I get an error that the return value is a double[]

我认为这会工作,但我得到一个错误,返回值是双[]

I think I either don't understand the map method or I'm goin about this all wrong in general (I looked at the ByteBuffer class, but it seems like a pain to implement this with it)

我想我要么不理解map方法,要么我总是把这个都搞错了(我看了一下ByteBuffer类,但用它来实现它似乎很痛苦)

Thanks in advance

提前致谢

4 个解决方案

#1


1  

You can use ByteBuffer for it:

您可以使用ByteBuffer:

double[] doubles = new double[] {1,2,3,4,5};
ByteBuffer buffer = ByteBuffer.allocate(doubles.length * Double.BYTES);
Arrays.stream(doubles).forEach(buffer::putDouble);
buffer.array();

#2


2  

You can't cast a double[] to a byte[] for the fundamental reason that they are unrelated types, and you can only cast between related types.

由于它们是不相关的类型的基本原因,您不能将double []转换为byte [],并且只能在相关类型之间进行转换。

Casts in Java, unlike, say, C++, don't actually create a new object: they are merely a way to the compiler "I know more about the type of this object than you; trust me." For example, you might know that a variable of type Object actually holds a reference to a String, something which the compiler cannot know; in that case, you can cast the reference.

与C ++不同,Java中的强制转换实际上并不创建新对象:它们只是编译器的一种方式“我比你更了解这个对象的类型;相信我。”例如,您可能知道Object类型的变量实际上包含对String的引用,这是编译器无法知道的;在这种情况下,您可以转换引用。

You can, however, construct a new array:

但是,您可以构造一个新数组:

byte[] output = new byte[input.length];
for (int j = 0; j < input.length; j++) {
  output[j] = (byte) input[j];
}

There is no way to do this with streams. Or rather, there is, in that you could crowbar this code into a stream operation on a Stream<double[]>, say; but involving streams like that clearly adds no benefit.

使用流无法做到这一点。或者更确切地说,你可以将这段代码扼流到Stream 上的流操作中,比如说;但涉及这样的流明显没有任何好处。

#3


0  

Java Streams is not the right tool here, especially not since there is no ByteStream in Java.

Java Streams不是正确的工具,特别是因为Java中没有ByteStream。

Your method can be implemented as a simple for loop.

您的方法可以实现为简单的for循环。

@Override
public byte[] getBytes() {
    byte[] arr = new byte[driveVector.length];
    for (int i = 0; i < arr.length; i++)
        arr[i] = (byte) driveVector[i];
    return arr;
}

#4


0  

In my MQTT application I read a single double value and post that to the broker. However, there is no real difference between a single and an array of doubles. The client needs to know the array length, while with a single value it always knows there is one.

在我的MQTT应用程序中,我读取了一个double值并将其发布到代理。但是,单个和双数组之间没有真正的区别。客户端需要知道数组长度,而使用单个值时,它总是知道有一个。

I'm confident that you can adapt my code to writing multiple values, adapt the toMessage to write multiple double values.

我相信你可以调整我的代码来编写多个值,调整toMessage来编写多个double值。

public abstract class SensorMonitor {
  protected final MqttAsyncClient client;
  protected final String topic;
  protected final Logger logger = Logger.getLogger(getClass().getName()); 
  private final ByteArrayOutputStream byteOut = new ByteArrayOutputStream(8);
  private final DataOutputStream dataOut = new DataOutputStream(byteOut);

  public SensorMonitor(MqttAsyncClient mqttClient, String topic) {
    this.client = mqttClient;
    this.topic = topic;
  }

  public void start(ScheduledExecutorService service) {
    service.scheduleWithFixedDelay(this::publish, 0, 30, TimeUnit.SECONDS);
  }

  protected void publish() {
    try {
        MqttMessage message = toMessage(readNewValue());
        client.publish(topic, message);

    } catch (MqttException | IOException e) {
        logger.log(Level.SEVERE, "Could not publish message", e);
    }
  }

  private MqttMessage toMessage(double value) throws IOException {
    byteOut.reset();
    dataOut.writeDouble(value);
    return new MqttMessage(byteOut.toByteArray());
  }

  protected abstract double readNewValue();
}

The DataOutputStream.writeDouble uses Double.doubleToLongBits to create a IEEE 754 floating-point "double format" bit layout.

DataOutputStream.writeDouble使用Double.doubleToLongBits创建IEEE 754浮点“双格式”位布局。

In my case I could pre-alloc and reuse the byteOut output stream as I knew upfront the needed size of the byte[].

在我的情况下,我可以预先分配和重用byteOut输出流,因为我事先知道byte []所需的大小。

#1


1  

You can use ByteBuffer for it:

您可以使用ByteBuffer:

double[] doubles = new double[] {1,2,3,4,5};
ByteBuffer buffer = ByteBuffer.allocate(doubles.length * Double.BYTES);
Arrays.stream(doubles).forEach(buffer::putDouble);
buffer.array();

#2


2  

You can't cast a double[] to a byte[] for the fundamental reason that they are unrelated types, and you can only cast between related types.

由于它们是不相关的类型的基本原因,您不能将double []转换为byte [],并且只能在相关类型之间进行转换。

Casts in Java, unlike, say, C++, don't actually create a new object: they are merely a way to the compiler "I know more about the type of this object than you; trust me." For example, you might know that a variable of type Object actually holds a reference to a String, something which the compiler cannot know; in that case, you can cast the reference.

与C ++不同,Java中的强制转换实际上并不创建新对象:它们只是编译器的一种方式“我比你更了解这个对象的类型;相信我。”例如,您可能知道Object类型的变量实际上包含对String的引用,这是编译器无法知道的;在这种情况下,您可以转换引用。

You can, however, construct a new array:

但是,您可以构造一个新数组:

byte[] output = new byte[input.length];
for (int j = 0; j < input.length; j++) {
  output[j] = (byte) input[j];
}

There is no way to do this with streams. Or rather, there is, in that you could crowbar this code into a stream operation on a Stream<double[]>, say; but involving streams like that clearly adds no benefit.

使用流无法做到这一点。或者更确切地说,你可以将这段代码扼流到Stream 上的流操作中,比如说;但涉及这样的流明显没有任何好处。

#3


0  

Java Streams is not the right tool here, especially not since there is no ByteStream in Java.

Java Streams不是正确的工具,特别是因为Java中没有ByteStream。

Your method can be implemented as a simple for loop.

您的方法可以实现为简单的for循环。

@Override
public byte[] getBytes() {
    byte[] arr = new byte[driveVector.length];
    for (int i = 0; i < arr.length; i++)
        arr[i] = (byte) driveVector[i];
    return arr;
}

#4


0  

In my MQTT application I read a single double value and post that to the broker. However, there is no real difference between a single and an array of doubles. The client needs to know the array length, while with a single value it always knows there is one.

在我的MQTT应用程序中,我读取了一个double值并将其发布到代理。但是,单个和双数组之间没有真正的区别。客户端需要知道数组长度,而使用单个值时,它总是知道有一个。

I'm confident that you can adapt my code to writing multiple values, adapt the toMessage to write multiple double values.

我相信你可以调整我的代码来编写多个值,调整toMessage来编写多个double值。

public abstract class SensorMonitor {
  protected final MqttAsyncClient client;
  protected final String topic;
  protected final Logger logger = Logger.getLogger(getClass().getName()); 
  private final ByteArrayOutputStream byteOut = new ByteArrayOutputStream(8);
  private final DataOutputStream dataOut = new DataOutputStream(byteOut);

  public SensorMonitor(MqttAsyncClient mqttClient, String topic) {
    this.client = mqttClient;
    this.topic = topic;
  }

  public void start(ScheduledExecutorService service) {
    service.scheduleWithFixedDelay(this::publish, 0, 30, TimeUnit.SECONDS);
  }

  protected void publish() {
    try {
        MqttMessage message = toMessage(readNewValue());
        client.publish(topic, message);

    } catch (MqttException | IOException e) {
        logger.log(Level.SEVERE, "Could not publish message", e);
    }
  }

  private MqttMessage toMessage(double value) throws IOException {
    byteOut.reset();
    dataOut.writeDouble(value);
    return new MqttMessage(byteOut.toByteArray());
  }

  protected abstract double readNewValue();
}

The DataOutputStream.writeDouble uses Double.doubleToLongBits to create a IEEE 754 floating-point "double format" bit layout.

DataOutputStream.writeDouble使用Double.doubleToLongBits创建IEEE 754浮点“双格式”位布局。

In my case I could pre-alloc and reuse the byteOut output stream as I knew upfront the needed size of the byte[].

在我的情况下,我可以预先分配和重用byteOut输出流,因为我事先知道byte []所需的大小。