使用GRIB2Tools访问GRIB数据时出现IndexOutOfBoundException异常
问题描述
我正在处理GRIB2预报文件,在使用GRIB2Tools库时遇到了问题。
我有一个代表GRIB2数据集内容的Array[Byte],为了获取特定位置的数值,我将该变量的内容写入文件,再加载为InputStream,用于调用getValueAtLocation(id, lat, long)或interpolateValueAtLocation(id, lat, long)方法。我可以正常读取文件的元数据,但只要调用上述两个方法之一,就会抛出IndexOutOfBoundException。
以下是我用来将GRIB2字节数组(变量名为bytes)写入文件、再加载为InputStream的Scala代码:
val file: File = new File("my-data.grib") val temp = FileUtils.writeByteArrayToFile(file, bytes) val input = new FileInputStream("my-data.grib") val grib: RandomAccessGribFile = new RandomAccessGribFile("my-grib", "my-data.grib") grib.importFromStream(input, 0)
根据库的说明文档,我的用法是正确的,对吗?
之后我可以从GRIB2文件中顺利读取以下元数据:
Body format : GRIB2 Date: 12.10.2021 Time: 9:0.0 Generating centre: 85 Forecast time: 5 Parameter category: 0 Parameter number: 0 Covered area: from (latitude, longitude): 51.47, 348.0 to: (latitude, longitude): 37.5, 16.0
当我传入id = 0、lat = 48、long = 2(读取元数据可知该坐标在覆盖范围内)调用getValueAtLocation(id, lat, long)和interpolateValueAtLocation(id, lat, long)时,得到如下报错:
java.lang.IndexOutOfBoundsException at java.nio.Buffer.checkIndex(Buffer.java:551) at java.nio.HeapByteBuffer.getShort(HeapByteBuffer.java:327) at com.ph.grib2tools.grib2file.RandomAccessGribFile.interpolateValueAt(RandomAccessGribFile.java:196) at com.ph.grib2tools.grib2file.RandomAccessGribFile.interpolateValueAtLocation(RandomAccessGribFile.java:133)
报错位置指向RandomAccessGribFile.java:196的这一行代码:
float val11 = sec5.calcValue(ByteBuffer.wrap(data).getShort((jidx1*gridDefinition.numberPointsLon+iidx1)*bytesperval));
请问是我的使用方法有误,还是库源码或GRIB文件存在问题?该文件来自国家预报机构,应该是合规的。我附上了用Panoply软件导出的GRIB2文件结构截图。
问题排查与解决建议
你的使用流程符合库的设计要求,问题根因是GRIB2Tools库的兼容缺陷,排查方向如下:
- 跨本初子午线的经度范围处理异常:你读取到的元数据经度范围为348.0°到16.0°,属于跨0°经线的格点定义(348.0°等价于-12°),库在计算坐标对应的格点索引时,没有兼容0~360°范围的经度表示,导致计算出的横向格点索引超出实际格点数量,最终触发ByteBuffer越界。
- 数据位宽不匹配:报错行默认按2字节读取格点值,如果你的GRIB2文件数据表示节定义的单值字节宽度不是2,会导致偏移量计算错误,触发越界。
你可以按以下步骤解决问题:
- 确认传入经度的表示范围:如果库内部默认使用-180180°的经度范围,将你传入的2°保持原值即可;如果库默认使用0360°范围,不需要做转换直接传入即可,先排除坐标转换的问题。
- 打印三个核心参数校验:输出
gridDefinition.numberPointsLon(横向格点数量)、gridDefinition.numberPointsLat(纵向格点数量)和bytesperval(单值字节宽度),和Panoply中读取到的文件参数做对比,如果不一致就是库解析元数据出错,手动修正参数后再调用取值方法即可。 - 如果确认是库的兼容问题,可直接读取数据段按GRIB2规范手动解码,自行实现坐标索引和插值逻辑,规避库的已知缺陷。
内容的提问来源于stack exchange,提问作者Karzyfox
相关产品推荐
相关产品推荐

