存取blob二进制数据出现较大偏差的一个可能的原因

2 篇文章 0 订阅
1 篇文章 0 订阅

工作的时候遇到了一个问题,另一个项目组将点的墨卡托坐标、索引等信息通过他们的客户端(类似于PHP中的pack()函数)装入二进制字符串,并以blob类型存入公共服务器中mysql数据库后,我在自己的电脑上远程调用服务器数据库中该二进制字符串数据并用unpack()函数解包,发现与存入的数据差别巨大,导致数据不能用,试了各种方法(比如修改unpack()函数的第一个参数,即解包数据时所使用的格式)都不行,最后发现可能是不同的设备读取二进制字符串数据的顺序不同,只需将二进制字符串反转便可正确读取数据。现把问题简化如下:

1.在mysql中建立数据库和相应的表,语句如下:

CREATE DATABASE dataflow;
USE dataflow;
CREATE TABLE blobtable(point blob);

2.将点的墨卡托坐标及索引存储为blob二进制数据,代码如下(save.php):

<?php
$conn=mysql_connect('192.168.0.1','username','password') or die('数据库服务器连接错误!'.mysql_error());  //连接服务器上的mysql数据库
mysql_select_db('dataflow',$conn) or die('数据库访问错误!'.mysql_error());
mysql_query('set names gb2312');
class Point
{
    public $x;
    public $y;
    public $z;
    public $ID;
    function __construct()
    {
        $this->x=0;
        $this->y=0;
        $this->z=0;
        $this->ID=0;
    }
    function setvalue($xx,$yy,$zz,$id)
    {

        $this->x=$xx;
        $this->y=$yy;
        $this->z=$zz;
        $this->ID=$id;
    }
}
$point=new Point();
$point->setvalue(-25.279161864968,0.35924216354303,10.594307044536,1);
$blobdata=mysql_real_escape_string(pack('dddN',$point->x,$point->y,$point->z,$point->ID));  //使用mysql_real_escape_string()函数将特殊字符转义,否则将不能成功存入数据库
$query=mysql_query("INSERT INTO blobtable(point) values('$blobdata')",$conn);
if(!$query) echo '插入数据失败!'.mysql_error();
else echo '插入成功!';
mysql_close($conn);
?>

3.读取二进制数据,代码如下(read.php):

<?php
$conn=mysql_connect('192.168.0.1','username','password') or die('连接数据库服务器错误!'.mysql_error());
mysql_select_db('dataflow') or die('数据库访问错误!'.mysql_error());
mysql_query('set names gb2312',$conn);
$sql=(mysql_query("select point from blobtable"));
$point=mysql_fetch_row($sql);
$data=unpack('dx/dy/dz/NID',$point[0]);  //$point是一个数组,$point[0],即数组的第一个值,才是字符串
print_r($data);
?>

4.结果分析

另一个项目组运行类似save.php的文件(他们用的是C++),将点的墨卡托坐标、索引等信息装入二进制字符串,并以blob类型存入公共服务器中mysql数据库后,我在自己的电脑上运行read.php文件远程调用公共服务器数据库中该二进制字符串数据并解包,二者对数据所使用的格式是一致的($x,$y$z都是d - double类型,$ID都是N - unsigned long类型),按理说read.php的输出结果应该是:
Array ( [x] => -25.279161864968 [y] => 0.35924216354303 [z] => 10.594307044536 [ID] => 1)
但是实际的结果是:
Array ( [ID] => 1 [x] => 2.2804399621849E+252 [y] => -8.8752819196704E+80 [z] => 1.5982655925763E+203 )
显然读取的x,y和z的值都是非常大的数,与存入的值有巨大差别,不能正常使用。在尝试过各种方法后发现可能是不同的设备存储读取二进制字符串数据的顺序不同,于是试着将二进制字符串用strrev()函数反转,便可正确读取数据。考虑到读取的ID的值是正确的,于是将ID与坐标分开读取,并将保存坐标信息的二进制字符串反转后解包,修改read.php代码如下:

<?php
$conn=mysql_connect('192.168.0.1','username','password') or die('连接数据库服务器错误!'.mysql_error());
mysql_select_db('dataflow') or die('数据库访问错误!'.mysql_error());
mysql_query('set names gb2312',$conn);
$sql=(mysql_query("select point from blobtable"));
$point=mysql_fetch_row($sql);
$data=unpack('dx/dy/dz',substr($point[0],0,24)); //$x,$y$z都是double类型,分别占8个字符,共占24个字符
$ID=unpack('NID',substr($point[0],24,28));  //$IDint类型,占4个字符
$data['ID']=$ID['ID'];
print_r($data);
?>

修改read.php之后再运行,结果如下:
Array ( [ID] => 1 [x] => -25.279161864968 [y] => 0.35924216354303 [z] => 10.594307044536 )
这样读取的x,y,z和ID的值就都是正确的,当时心情非常激动,找bug调试的过程是痛苦的,但是当找出bug之后喜悦之情也会溢于言表,尽管可能只需要修改很少的东西就可以将bug修复。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值