将float转换为Big Endian

时间:2017-10-22 03:50:38

标签: scala formatting jvm

我有一个从文件中读取的浮点数据。 但我知道它是Little-endian形式。 为了理解它,我需要将其转换为Big-endian。

我该怎么做?

这是我目前的代码:

<a href="http://www.pfpenergy.co.uk/media/1184/help-and-support">
    <img src="http://www.pfpenergy.co.uk/media/1184/help-and-support.png"/>
</a>

2 个答案:

答案 0 :(得分:1)

您可以使用ByteBufferByteOrder来处理结尾。在Holger's回答后得到了改进:

import java.nio._
import java.io._
import scala.annotation.tailrec
import scala.util.{Try, Success, Failure}

object FloatBigEndialLittleEndian {
    val floatSize: Int = java.lang.Float.SIZE / 8

    def main(args: Array[String]): Unit = {
        println(s"Float size: $floatSize")
        // floats in little endian (1, 2, 3, 4, 5)
        val littleEndians = Array[Int](0x0000803f, 0x00000040, 
                                       0x00004040, 0x00008040, 
                                       0x0000a040)

        val bs = new ByteArrayInputStream(getBytes(littleEndians))
        val ds = new DataInputStream(bs)

        val floats = toBigEndians(ds)
        println(floats)

        ds.close()
        bs.close()

    }
    // it just helper method to get Array[Byte] and create DataInputStream
    def getBytes(rawData: Array[Int]): Array[Byte] = {
        val b = ByteBuffer.allocate(rawData.length * floatSize)
        b.order(ByteOrder.BIG_ENDIAN)
        rawData.foreach(f => b.putInt(f))
        b.rewind()
        return b.array()
    }

    def toBigEndians(stream: DataInputStream): Seq[Float] = {
        val bf = streamToByteBuffer(stream)
        // rewind the buffer to make it ready for reading
        bf.rewind()

        // when we read, we want to get it in BIG_ENDIAN
        val floatBuffer = bf.order(ByteOrder.LITTLE_ENDIAN).asFloatBuffer();
        val n = floatBuffer.remaining

        @tailrec
        def floatBufferToArray_(idx: Int, floats: Array[Float]):  Array[Float] = {
            if (floatBuffer.hasRemaining) {
                // floatBuffer.get returns current an increments position
                floats(idx) = floatBuffer.get
                floatBufferToArray_(idx + 1, floats)
            }
            else floats
        }
        // allocate result float array
        val floatArray = Array.ofDim[Float](n)
        floatBufferToArray_(0, floatArray)
    }
    def streamToByteBuffer(stream: DataInputStream): ByteBuffer = {
        @tailrec
        def streamToByteBuffer_(stream: DataInputStream, 
                               bf: ByteBuffer): ByteBuffer = {
            Try(bf.put(stream.readByte())) match {
                case Success(_) => streamToByteBuffer_(stream, bf)
                case Failure(ex) if ex.isInstanceOf[EOFException] => bf
                case Failure(ex) => throw ex
            }
        }
        // pre-allocate with the size of the stream
        val bf = ByteBuffer.allocateDirect(stream.available)
        streamToByteBuffer_(stream, bf)
    }
}

答案 1 :(得分:1)

Artavazd Balayan’s answer正指向正确的方向。 ByteBuffer允许将其内容解释为Big Endian或Little Endian,如您所愿,并且是该工作的正确工具。

但是当你使用它时,就不再需要DataInputStream了。您可以直接使用ByteBuffer进行转移。

有效处理它的Java代码可能如下所示:

static float[][] bilToArray(Path dataFile, int nRows, int nCols) throws IOException {
    try(ReadableByteChannel fch = Files.newByteChannel(dataFile, StandardOpenOption.READ)){
        float[][] matrix = new float[nRows][nCols];
        ByteBuffer bb = ByteBuffer.allocateDirect(Float.BYTES*nRows*nCols);
        while(bb.hasRemaining()) if(fch.read(bb)<0) throw new EOFException();
        bb.flip();
        FloatBuffer fb = bb.order(ByteOrder.LITTLE_ENDIAN).asFloatBuffer();
        for(float[] row: matrix) fb.get(row);
        return matrix;
    }
}

如果文件非常大并且您知道它始终位于默认文件系统中,您甚至可以使用Memory-mapped file

static float[][] bilToArray(Path dataFile, int nRows, int nCols) throws IOException {
    try(FileChannel fch = FileChannel.open(dataFile, StandardOpenOption.READ)) {
        float[][] matrix = new float[nRows][nCols];
        ByteBuffer bb = fch.map(FileChannel.MapMode.READ_ONLY, 0, Float.BYTES*nRows*nCols);
        FloatBuffer fb = bb.order(ByteOrder.LITTLE_ENDIAN).asFloatBuffer();
        for(float[] row: matrix) fb.get(row);
        return matrix;
    }
}

将此转换为Scala应该不会那么难。