在R中解析GPS文件的8字节大端有符号整数问题
8字节大端有符号整数的R解析方案
问题场景
需解析GPS应用导出轨迹文件中的8字节大端有符号整数,包含以下三类数据:
- 纬度:北纬度数×10^7,示例原始数据解析后应为
377441228 - 经度:示例原始数据解析后应为
-1195899101 - 时间戳:示例原始数据解析后应为
1618678057000
原始数据示例:
# 应解析为377441228 lat = as.raw(c(0x00, 0x00, 0x00, 0x00, 0x16, 0x7f, 0x4b, 0xcc)) # 应解析为-1195899101 lon = as.raw(c(0xff, 0xff, 0xff, 0xff, 0xb8, 0xb8, 0x07, 0x23)) # 应解析为1618678057000 time = as.raw(c(0x00, 0x00, 0x01, 0x78, 0xe0, 0xbb, 0x08, 0x28))
此前尝试的两种方法均存在缺陷:
readBin()方法:对lat和lon解析正确,但time因超出R基础integer类型(32位)的范围,解析结果溢出错误- 字符串转数值方法:对
lat和time解析正确,但lon作为有符号负数被当成无符号正数处理,结果错误
正确解析方案
方案1:使用bit64包处理64位整数
R基础包的integer仅支持32位,无法容纳8字节大整数。bit64包提供的integer64类型可原生支持64位有符号整数解析:
# 先安装包(首次使用时执行) install.packages("bit64") library(bit64) # 解析纬度 readBin(lat, what = integer64(), size = 8, signed = TRUE, endian = 'big') # 输出:377441228 # 解析经度 readBin(lon, what = integer64(), size = 8, signed = TRUE, endian = 'big') # 输出:-1195899101 # 解析时间戳 readBin(time, what = integer64(), size = 8, signed = TRUE, endian = 'big') # 输出:1618678057000
方案2:手动实现有符号转换(无第三方依赖)
若不想引入外部包,可手动处理无符号转有符号的逻辑,用numeric类型存储结果:
parse_8byte_signed <- function(raw_vec) { # 将原始字节拼接为十六进制字符串 hex_str <- paste(raw_vec, collapse = "") # 转为无符号数值 unsigned_val <- strtoi(paste0("0x", hex_str), base = 16) # 8字节有符号整数的范围是[-2^63, 2^63-1],若数值>=2^63则为负数,需减去2^64 if (unsigned_val >= 2^63) { unsigned_val - 2^64 } else { unsigned_val } } # 解析纬度 parse_8byte_signed(lat) # 输出:377441228 # 解析经度 parse_8byte_signed(lon) # 输出:-1195899101 # 解析时间戳 parse_8byte_signed(time) # 输出:1618678057000
内容的提问来源于stack exchange,提问作者Dan Hicks
相关产品推荐
相关产品推荐

