读取spark中的双精度二进制文件会产生错误的输出

时间:2016-12-15 16:33:07

标签: scala apache-spark binaryfiles

我有一个用C生成的二进制文件。 该文件的固定记录长度为26000双,并包含1067条没有分隔符的记录。我需要在spark中读取它并获得double值。 我还有一个Python代码,它获取双打的值,并在spark-shell中使用来自java的Files.readAllBytes我也得到了这些值,所以根据Python输出我希望第一个记录的前1000个双打有值-3509.580466022612。 取自火花壳:

import java.nio.ByteBuffer
import java.nio.ByteOrder
val doubleByteSize = 8
val recordLength = 1000 * 26 * doubleByteSize
val bytesRdd = sc.binaryRecords("file:///myBinaryFile.val", recordLength)
val arrayOfRecords = bytesRdd.collect
val firstRecord = arrayOfRecords(0)
// group 8 bytes together to transform them to doubles
val listOfDoubles = firstRecord.grouped(doubleByteSize).toList
// I get 1000 times the same double but isn't -3509.580466022612 it's 1.1848107264484659E181
val result = listOfDoubles.map(arrayOfBytes => ByteBuffer.wrap(arrayOfBytes).getDouble)
// try with little endian and it is wrong again -6.045003065652023E-27
val result2 = listOfDoubles.map(arrayOfBytes => ByteBuffer.wrap(arrayOfBytes).order(ByteOrder.LITTLE_ENDIAN).getDouble)

记录数看起来正确(arrayOfRecords.length = 1068),每条记录的字节数对我来说看起来不错(firstRecord.length = 208000),前1000个双打包含相同的值,所有内容都符合预期但是双值(1.1848107264484659E181)不是预期值(-3509.580466022612)。我试图把它改成小端,但数字仍然是错误的(-6.045003065652023E-27)。 Python代码:

def str_all(data):
 ret_str = ""
 for d in data:
    ret_str+= " " + str(d)
 return ret_str

def main():

 num_sim = 1000
 num_ts = 26

 record_index = 0

 deal_data = array('d')
 with open("/myBinaryFile.val","rb") as data_file:
    data_file.seek(SIZEOFDOUBLE*record_index*num_sim*num_ts)
    deal_data.fromfile(data_file,num_sim*num_ts)
 ts_index = 0
 deal_range = slice(ts_index*num_sim,(ts_index+1)*num_sim)  
 # it prints 1000 times -3509.580466022612
 print(str_all(deal_data[deal_range]))

读取二进制文件(来自spark-shell)的简单java代码获得预期值:

val byteArray = Files.readAllBytes(Paths.get("/mybinaryFile.val"))
// gets the correct value -3509.580466022612
ByteBuffer.wrap(byteArray).order(ByteOrder.LITTLE_ENDIAN).getDouble

任何人都知道这里发生了什么?

提前致谢。

Spark版本1.6.0,使用Scala版本2.10.5(Java HotSpot(TM)64位服务器VM,Java 1.7.0_67) Python版本2.6

1 个答案:

答案 0 :(得分:0)

当我这样做时,问题与二进制数据本身无关:

val arrayOfRecords = bytesRdd.collect
val firstRecord = arrayOfRecords(0)

我没有订购数组,更改解决了这个问题:

val firstRecord = bytesRdd.first

看起来像collect不保留订单。感谢Archetypal Paul的时间和帮助。