背景

公司做的一个气象数据显示项目,其中涉及到很多原始格式的数据解析,比如格点气象数据,内部数据一般就是二维数组,在存储的时候,一般采用二进制方式进行存储。

格点数据的本质,可以理解成一个图片,每一个像素点上有一个数据值。

任务

我接手做这个解析工作,就是要将二进制格式的数据,转化为更为通用的文本格式,方便查看和显示。
另外一项附加任务,则是因为原始数据的密度较高,是1公里x1公里的密度,其纵向有435公里,横向有355公里,总共涉及435x355=154425个点,由于前端优化不太给力,只能对密度降级,变成5公里x5公里的密度。

解析代码

所谓二进制数据,就是将数据一个一个往后面码,所以代码也不难,劈里啪啦一阵敲,就完成了:

// InputStream in; 流对象
float[][] data = new float[HEIGHT][WIDTH];//使用float数组接收数据
byte[] buf = new byte[2];//buf
BufferedInputStream bin = new BufferedInputStream(in);//使用缓存流对象
for(int y=0; y<HEIGHT; y++) {//从左上,逐行读取
    for(int x=0; x<WIDTH; x++) {
          data[y][x] = read(bin, buf);//读取一个数据
    }
    skip(bin,WIDTH*5*2*4);//往下跳过4行
}

问题

数据本来的样子是:
显示效果

我解析出来之后,将结果放入到显示界面中查看,解析的结果最终出来却是条纹状的数据。

而令人崩溃的是:
但是如果我没有进行密度降级的时候,又是正常的(将原始宽度、高度逐一解析,而不进行跳行)。

过程

中间是一个痛苦的试错过程,我尝试打印当前流的位置,因为这个形状看起来像是一个错位导致的,然而我通过一个position去记录,发现是正常的。

转机

在通过的过程中,我时不时的告诉自己,这一定是哪些写的有问题。
一个偶然的想法,我在创建缓存流的时候,加入一个参数size=3550(刚好是5行的大小)

BufferedInputStream bin = new BufferedInputStream(in, 3550);

诶!

这就是我想要的。
让我不禁想起那首歌——《我的滑板鞋》。

原因

其实很简单,问题就出现在

skip(bin,WIDTH*5*2*4);//往下跳过4行

而我是这样写的(这样写,是为了避免抛出checkedException)

try {
      inputStream.skip(n);
}catch (Exception ex){
      throw new RuntimeException("reading data error:", ex);
}

也就是我以为,这个skip会确保真实跳过所需要的字节数,然后查到BufferedInputStream的skip方法

      public synchronized long skip(long n) throws IOException {
        this.getBufIfOpen();
        if (n <= 0L) {
            return 0L;
        } else {
            long avail = (long)(this.count - this.pos);
            if (avail <= 0L) {
                if (this.markpos < 0) {
                    return this.getInIfOpen().skip(n);
                }

                this.fill();
                avail = (long)(this.count - this.pos);
                if (avail <= 0L) {
                    return 0L;
                }
            }

            long skipped = avail < n ? avail : n;
            this.pos = (int)((long)this.pos + skipped);
            return skipped;
        }
    }

可以看出,BufferedInputStream并不会确保跳过所需要的字节数——如果所跳过的字节超过当前的缓存长度,则只会跳到当前缓存的末尾。

由此,我以为它跳到了X位置,实际上它还在原来的地方——所以,这也是为什么条纹状会出来的原因。

解决

知道原因,解决办法就比较多了

  • 调整参数方法:就是上面写上3550作为参数,确保刚好跳到指定的位置;
  • do-while循环确保:当小于跳过数时,继续往前跳
      do{
            n -= inputStream.skip(n);
      }while(n>0);
  • 不使用BufferedInputStream
    直接使用原始的FileInputStream读取并不会存在这个问题,当skip在最终的字节流上进行移动时,会真实有效。

最后采用:3550参数,同时为防止将来可能出问题,也做了do-while的判断。

总结

如标题所说,我真傻,真的,我单知道InputStream.read,可能会读取的长度可能会不够,可是我却不知道skip跳过的长度也会不够。
所谓基础不牢,地动山摇,加强学习加强基础很重要!

posted @ 2020-09-19 10:31 小彬 阅读(473) 评论(0) 推荐(0) 编辑
摘要: 起因 客户说:“今天的预报又没有发出去,帮忙看下怎么回事?” “...” 经过 登陆服务器,发现程序一直在打印 这是代码中写的 程序通过启动ActiveMQ,然后判断是否仍有消息在处理,如果在处理就Sleep当前线程,等待处理完毕 当接收到消息时的处理主逻辑: 那么问题应该是 或者 一直在处理,卡住 阅读全文
posted @ 2019-06-16 10:58 小彬 阅读(626) 评论(0) 推荐(2) 编辑
摘要: 起因 周六,7:10,闹钟还没响,客户电话过来了。 “彬哥,我们XX平台XX功能导致数据库死锁了,上次某某上去看过,把死锁的sqlserver进程杀过,但还是出现这个问题,麻烦你看一下” “...” 起床,嗽口,吃个西红柿当早餐,出门(家里没网) 经过 连接服务器,重现问题 问题是: 某功能,点击之 阅读全文
posted @ 2019-06-15 09:46 小彬 阅读(887) 评论(0) 推荐(1) 编辑
摘要: sl4j或者log4j中,推荐的记录方式是: private Logger log = Logger.getLogger(getClass()); //或者 private static final Logger log = Logger.getLogger(XXX.class); //调用 log 阅读全文
posted @ 2017-01-19 16:58 小彬 阅读(2440) 评论(4) 推荐(2) 编辑
摘要: 阅读对象 搭框架人员,或者其他感兴趣的开发人员 背景 一般来说在业务代码中,加上 , ,`@Repository @Controller`等注解就可以实现将bean注册到Spring中了。 但是在写框架,可能有些类会动态生成,怎么动态注册到Spring中呢? 接口 BeanDefinitionReg 阅读全文
posted @ 2016-12-30 15:12 小彬 阅读(7631) 评论(0) 推荐(3) 编辑
摘要: 且看一下有多少个 列举一下XXUtil/XXUtils恶劣之处 1. 不知道该用XXUtil还是用XXUtils, 或者XXHelper, XXTool 2. 不知道该用a.jar中的XXUtil还是b.jar中的 3. 在一个工程里, 同名的Util居然引入的不是一个jar包中的 4. 不知道在哪 阅读全文
posted @ 2016-11-30 16:36 小彬 阅读(8548) 评论(4) 推荐(1) 编辑
摘要: c 一年一个变化,给c 的学习者带来困惑! C 马上要7.0了! .net要变成.net core了! 现在版本这么多,保不准公司与公司之间,使用的版本就不一样。 举个例子: A同学从甲公司跳到乙公司 情况一:版本一致,庆幸吧 情况二:乙公司版本高,然后A同学看不懂乙公司的代码,然后A同学还是老的代 阅读全文
posted @ 2016-06-14 11:07 小彬 阅读(916) 评论(3) 推荐(2) 编辑
摘要: String dateString = "2014101517";new SimpleDateFormat("yyyyMMddHH").parse(dateString)这句代码会产生错误吗?答案是:不会。这里是直接赋值给dateString一个值,这么解析是不会有问题的。但是当这个字符串是来自文件... 阅读全文
posted @ 2014-10-15 17:51 小彬 阅读(5668) 评论(0) 推荐(0) 编辑
摘要: 《自控力》书中提到一个科学实验,对我影响最大! 实验是这样的: 话说有两位年轻科学家,在做一个小白鼠实验。他们将电极插入到小白鼠的大脑中,因为他们技术不过关,插错位置了,原本小白鼠应该非常害怕电击的,变得非常喜欢电击。他们将之称之为“快感中心”——意思如果使用电击大脑的这个位置,就会非常快乐。 后来... 阅读全文
posted @ 2014-08-24 14:48 小彬 阅读(4677) 评论(6) 推荐(1) 编辑
摘要: 在企业管理系统中,常常有这样的要求: 1. 用户一般只能查看自己部门的数据 2. 可以设置用户可以查看哪些部门的数据 这种权限的控制,一般称为数据权限,与之对应的功能权限,则是系统中哪些功能可以使用——①菜单、按钮等元素能正常显示;②如果用户访问了本身不可见的功能,系统也能阻止(访问控制)。 开发时间长了,就发现编程一般就是两个问题: 1. 在哪里设置(数据从哪里来... 阅读全文
posted @ 2014-08-04 14:04 小彬 阅读(25332) 评论(4) 推荐(2) 编辑
点击右上角即可分享
微信分享提示