Perl利用pack/unpack处理二进制文件

perl的强项在于处理文本文件. 针对二进制文件, 利用pack/unpack函数同样可以进行很好的处理.

这里利用nginx的缓存文件做个小例子:)

nginx描述缓存文件属性的数据结构
1
2
3
4
5
6
7
8
9
typedef struct {
    time_t                           valid_sec;
    time_t                           last_modified;
    time_t                           date;
    uint32_t                         crc32;
    u_short                          valid_msec;
    u_short                          header_start;
    u_short                          body_start;
} ngx_http_file_cache_header_t;

以上是nginx的用于记录缓存文件信息的结构体, 下面是一个具体的nginx缓存文件:

nginx描述缓存文件属性的数据结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<99>!JR^@^@^@^@hT<fb>O^@^@^@^@^Y<ee>hP^@^@^@^@N<d1>e^W^@^@w^@<b2>^A;^X_
KEY: http://ajax.cloudflare.com/cloudflare.min.js
HTTP/1.1 200 OK^M
Server: cloudflare-nginx^M
Date: Mon, 01 Oct 2012 01:12:57 GMT^M
Content-Type: application/x-javascript^M
Last-Modified: Mon, 09 Jul 2012 22:00:08 GMT^M
Connection: close^M
Vary: Accept-Encoding^M
Expires: Tue, 01 Oct 2013 01:12:57 GMT^M
Cache-Control: public, max-age=31536000^M
Content-Encoding: gzip^M
^M
http-body

简单介绍下, nginx的缓存文件中首行是之前所述的结构体, 第二行是缓存文件所对应的缓存文件, 接下来就是http头以及正文.(这里提醒下: 如果用vim编辑二进制文件时记得使用-b选项, 否在保存后可能会造成二进制内容的变化~)

现在, 我们需要取出并打印首行的结构体, 利用perl我们可以这么做:

perl读取结构体
1
2
perl -le '$line1=<>;@list = unpack "l l l I S S S", \
      $line1;print "@list"' cache_file     # 这里unpack的字符串可以改为"l3 I S3"

嗯, 同样的, 我们也可以将一串值搞成这样的一个二进制:

perl写入
1
2
perl -le '$param=shift;@data=split /\s+/,$param;\
      $str=pack "l3 I S3",@data;print $str' '1353920000 1345831111 1353921842 3389831111 0 100 500'

Over~

Comments