我有一个从文件中读取的浮点数据。 但我知道它是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>
答案 0 :(得分:1)
您可以使用ByteBuffer和ByteOrder来处理结尾。在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应该不会那么难。