Perl 读取二进制数据并将其转换为十六进制

Perl 读取二进制数据并将其转换为十六进制,perl,file-io,type-conversion,Perl,File Io,Type Conversion,我是perl新手。我试图编写从二进制文件读取数据并以特定格式返回的代码。它可以是十进制、无符号、十六进制。。。 在十六进制编辑器中打开的二进制文件如下所示: 7C 00 48 00 D6 00 E4 07 04 07 14 36 39 00 00 36 00 D6 00 44 CD 08 FF 00 00 00 00 FF 00 00 00 00 FF 00 00 00 00 FF 00 00 00 00 7C 00 48 00 D6 00 E4 07 04 07 14 37 02 00 00

我是perl新手。我试图编写从二进制文件读取数据并以特定格式返回的代码。它可以是十进制、无符号、十六进制。。。 在十六进制编辑器中打开的二进制文件如下所示:

7C 00 48 00 D6 00 E4 07 04 07 14 36 39 00 00 36 00 D6 00 44 CD 08 FF 00 00 00 00 FF 00 00 00 00 FF 00 00 00 00 FF 00 00 00 00 7C 00 48 00 D6 00 E4 07 04 07 14 37 02 00 00 36 00 D6 00 44 CE 07 FF 00 00 00 00 FF 00 00
我知道文件中每9个字节代表1个完整单元,其中包括6个变量:start一个1字节无符号整数,Devtype1字节有符号整数,以及4个字节hexDevUIDyear一个2字节无符号整数,均为1字节无符号整数。 下面是我的代码,它不能正常工作:

    #!/usr/bin/perl
    use feature qw(say);
    use strict;
    use warnings;
    
    
    use constant BUFSIZE => 9;
    my @input_file;
    
    @input_file = 'path\ZONE0.txt';
    
        open (my $BIN, "<:raw", $input_file[$i]) or die "can't open the file @input_file: $!";
        my $buffer;     
    
        while (1) {
            my $bytes_read = sysread $BIN, $buffer, BUFSIZE;
            die "Could not read file @input_file: $!" if !defined $bytes_read;
            last if $bytes_read <= 0;
            my @decimal= map { unpack "C", $_ } split //, $buffer;
            
            my $start= $decimal[0];
            
            my $DevType = $decimal[1];
            
            my @DevUID =@decimal[5,4,3,2];
            my $string_DevUID = join('', $string_DevUID);
            my $hexDevUID =sprintf("0x%x",$string_DevUID);
            
            
            
            my @year=@decimal[6,7];
            my $month=$decimal[8];
            my $day = $decimal[9];
            
            
            say $start;
            say $DevType;
            say $hexDevUID;
say @year;
        say $month;
        say $day;
        }
        

一旦有了缓冲区,就不要将其视为字符串<代码>解包立即使用正确的格式将其解包。不要将其拆分为chars,只是为了将其重新转换为ints:

use v5.10;
my $buffer =
    "\x7C" . "\x00\x48\x00\xD6" . "\x00" .
    "\xE4\x07" . "\x04" . "\x07";

my @values = unpack 'CNCSCC', $buffer;

say "@values";

N
可能是
V
。查看
pack
文档,了解您希望八位字节走哪条路

然后,一旦你有了数字,就用数字做一些事情(没有任何顺序和移位的意义。如果你
适当地解压它,你就不需要做这部分:

my @array = @decimal[5,4,3,2];
my $string_DevUID;
while( my( $i, $v ) = each @array ) {
    $string_DevUID += $v << ($i+1)
    }
my@array=@decimal[5,4,3,2];
我的$string_DevUID;
while(my($i,$v)=每个@数组){

$string_DevUID+=$v所以在我的头撞了几次墙之后,我得到了一个答案: 这是我修改的。我以原始二进制格式读取9个字节,这样我就不会弄乱任何东西。我的缓冲区现在是一个字节数组,而不是小数。 我后来相应地将数据从二进制转换为十六进制或十进制

while循环现在看起来是这样的:(我添加了一个从二进制转换为十进制的子例程。)

while(1){
my$bytes\u read=sysread$BIN、$buffer、BUFSIZE;
如果!定义了$bytes\u read,则die“无法读取文件@input\u file:$!”;

最后,如果$bytes\u读取,我很抱歉我不明白。N和v是什么?CNSCC是做什么的?我在解包文档中找不到太多事实上,
解包
点。我在中也有大量的例子。这真的不是一个好方法。如果你想要一个八位字节,使用C。那么你不必做任何事情就可以将其作为八位字节。另外,
 sprintf('0x%X',…)
在十六进制表示法之前获取
0x
,但这也是格式
%#X
已经为您提供的功能!
my @array = @decimal[5,4,3,2];
my $string_DevUID;
while( my( $i, $v ) = each @array ) {
    $string_DevUID += $v << ($i+1)
    }
while (1) {
            my $bytes_read = sysread $BIN, $buffer, BUFSIZE;
            die "Could not read file @input_file: $!" if !defined $bytes_read;
            last if $bytes_read <= 0;
            my @decimal= map { unpack "b8", $_ } split //, $buffer;
            
            my $stringstart= reverse split //, $decimal[0];
            my $start = bin2dec($stringstart);
            
            my $stringDevType= reverse split //, $decimal[1];
            my $DevType = bin2dec($stringDevType);
            
            my $stringDevUID = join('', $decimal[2], $decimal[3], $decimal[4], $decimal[5]);
            my $DevUID= reverse split //, $stringDevUID;
            my $HexDevUID = sprintf('%X', oct("0b$DevUID"));
            my $finalHexDevUID = '0x'.$HexDevUID;