5

我在 SQLite 数据库中有一个表,它存储用 LZ4 算法压缩的 blob。我正在尝试使用 Compress::LZ4 中的解压缩/解压缩函数,但没有取得任何成功。

示例 SQLite db 可以从这里下载

这是我连接到 SQLite db 并获取 blob 的方式:

use DBI; 
use Data::Dump; 
use MIME::Base64; 
use Compress::LZ4;    

my $dbh = DBI->connect("dbi:SQLite:dbname=$ARGV[0]","","");   
$sth = $dbh->prepare("select blob_data from blob_parts where data_fk = 6");
$sth->execute();   
$result = $sth->fetch;   
$blob = $result->[0];

dd $blob;
dd (decompress($blob));

$sth->finish();  
$dbh->disconnect;

对于我在此示例代码 (data_fk=6) 中选择的特定 blob,dd 输出以下内容:

"LZ4\1>\1\0\0\xF7\xD6df\xF1mBXML\1\xA1\aVersion\xA1\4Type\xA1\2Id\xA1\3Ref\xA1\4Size\xA1\3use\xA1\4expr\xA1\ 5value\xA1\4data\xA1/序列化\xA1\aPoints3\xA1\tuser_E\0\xF0\16\bvertices\xA1\6double\xA1\bhas_attr\xA1\16\n\0\xC7object_ids\xA1\n\f \0\xF1M\4item\xA1\tis_active\xA0~B\20\n\22\6\4\x8C\1\0\0\0\6\2\xAA\24\6\0\xA4\x82 \x88\2\x80\x82\x82\xA6B\26\6\b\x80\1B\30 \6\b\x88\2\3B\32\1\x93\6\0\0\0`\ xACu\xCF\xBF\0\0\0\0\xCC\xF8\xC2?\0\0\0\0\0\x004\@\0\0\0 \xAA\xEF\xA9\20\x001h \xC5\xB1\b\0\xD0\0\0\$\@\1B\34\x85B\36\x87B C\0\xF0\aB\"\6\0\x88\3B\$\x85\ 1B\"\6\0\x88\3B\$\x85\1\1\1"

但是解压缩/解压缩函数只返回 undef。未压缩的数据应该类似于(以下输出由 XML 转换器生成):

<?xml version="1.0" encoding="utf-8"?>
<MultiStreamDocument>
<!-- Stream 1 -->
<?xml version="1.0" encoding="utf-8"?>
<data xmlns="" Id="1" Type="Points3" Version="1 2 0 1 1">
    <user_data Size="0"></user_data>
    <vertices Size="2">
        <double>-0.24577860534191132</double>
        <double>0.14821767807006836</double>
        <double>20</double>
        <double>0.050656620413064957</double>
        <double>0.069418430328369141</double>
        <double>10</double>
    </vertices>
    <has_attr>false</has_attr>
    <has_object_ids>true</has_object_ids>
    <object_ids Size="2">
        <item Version="3">
            <is_active>false</is_active>
        </item>
        <item Version="3">
            <is_active>false</is_active>
        </item>
    </object_ids>
</data><!-- Stream size: 126 bytes -->
</MultiStreamDocument>

从这个 SQLite 数据库获取未压缩的 blob 数据的正确方法是什么?

4

1 回答 1

2

您的数据看起来像是 LZ4 压缩的,并以四个字节为前缀,"LZ4\1"大概是格式指示符

接下来的四个字节">\1\0\0"是一个小端原始大小字段,计算结果为 318 字节,这是合理的。库decompress函数需要这个字段

所以理论上,你应该可以写

$blob = substr($blob(4);
dd decompress($blob);

并得到正确的结果。然而,这也导致undef我的值,这表明数据以某种方式损坏

可以肯定的是,大部分数据最终都未压缩。长度字段后面的两个字节是"\xF7\xD6",表示后面的数据是 229 字节的文字数据(第一个字节的高位 nybl - 0xF - 加上第二个字​​节 - 0xD6 - 是 0xE5 或 229)。所以这部分数据

"df\xF1mBXML\1\xA1\aVersion\xA1\4Type\xA1\2Id\xA1\3Ref\xA1\4Size\xA1\3use\xA1\4expr\xA1\5value\xA1\4data\xA1/http://www.slb.com/Petrel/2011/03/Serialization\xA1\aPoints3\xA1\tuser_E\0\xF0\16\bvertices\xA1\6double\xA1\bhas_attr\xA1\16\n\0\xC7object_ids\xA1\n\f\0\xF1M\4item\xA1\tis_active\xA0~B\20\n\22\6\4\x8C\1\0\0\0\6\2\xAA\24\6\0\xA4\x82\x88\2\x80\x82\x82\xA6B\26\6\b\x80\1"

是字面的,可以通过它包含的可读文本的数量来猜测

接下来的两个字节"B\30"应指示应从其复制数据的已翻译缓冲区内的偏移量。不幸的是,它的计算结果为 6210,而正如我们所见,到目前为止,缓冲区只有 229 字节长。这大概是数据导致decompress函数停止并返回的地方undef

这是我能对你的数据做的最好的事情。我希望它有帮助

于 2015-12-25T21:31:29.737 回答