如何在perl中解析MS-DOS时间?

时间:2011-08-20 12:51:12

标签: perl dos

我正在使用perl读取二进制文件。在文件的标题中,有4个字节表示MS-DOS时间。我怎么读这个时间?我不熟悉这种格式。

我发现这是为了参考:http://www.vsft.com/hal/dostime.htm但我仍然不确定如何阅读它。

2 个答案:

答案 0 :(得分:2)

您不能使用pack,因为它总是希望从字节边界开始。其中一些值也跨越字节边界,因此您不希望处理单个字节(尽管单词可行)。只是掩盖和转移更容易。

在这个例子中,我设置了掩码,所以我不必过于考虑它,然后使用它们从字符串中获取值。我对DOS时间格式一无所知,但从我读过的内容来看,你必须将秒乘以2(注意它只有5位):

use 5.010;
use strict;
use warnings;

use Data::Dumper;

# seconds   minutes   hours    day    month   years from 1980
#  5 bits    6         5        5       4       7
my $datetime = 0b11011_000011_11111_01100_1011_0001000;

my $parsed = parse( $datetime );
print Dumper( $parsed );

sub parse {
    my( $datetime ) = @_;
    state $masks = make_masks();

    my %this = map {
        $_, ( $datetime & $masks->{$_}[0] ) >> $masks->{$_}[1]
        } keys %$masks;

    $this{seconds} *= 2;
    $this{years} += 1980;

    return \%this;
    }

sub make_masks {
    my %masks = (
        seconds => [ 0b11111,  27 ],
        minutes => [ 0b111111, 21 ],
        hours   => [ 0b11111,  16 ],
        day     => [ 0b11111,  11 ],
        month   => [ 0b1111,    7 ],
        years   => [ 0b1111111, 0 ],
        );  

    foreach my $key ( sort { $masks{$a}[1] <=> $masks{$b}[1] } keys %masks ) {
        $masks{$key}[0] <<= $masks{$key}[1];
        }

    return \%masks;
    }

我的输出只是一个哈希:

$VAR1 = {
          'seconds' => 54,
          'hours' => 31,
          'years' => 1988,
          'month' => 11,
          'minutes' => 3,
          'day' => 12
        };

答案 1 :(得分:2)

另一种方法:

sub mst {
  my $msdos_time = shift;
  my @t = map { ord }
          map { pack("b*", $_) }
          map { reverse($_) }
          unpack("A5 A6 A5 A5 A4 A7", unpack("b*", $msdos_time));
  my %d;
  @d{seconds,minutes,hours,day,month,year} = @t;
  $d{seconds} *= 2;
  $d{year} += 1980;
  return \%d;
}

如果$msdos_time以小端格式表示(我相信)它将如何在内存中布局,这将有效。

(显然链接的map - s可以合并 - 我这样写它是为了让它更容易看到发生了什么。)

示例:

print Dumper(mst("\x22\x12\x01\x41"));

# byte 0   | byte 1   | byte 2   | byte 3
# 76543210 | 76543210 | 76543210 | 76543210
#    S...s                                   seconds
# ..m             M..                        minutes
#            H...h                           hours
#                          D...d             day
#                       ..m               M  month
#                                  Y.....y   year
# 00100010 | 00010010 | 00000001 | 01000001

$VAR1 = {
      'seconds' => 4,
      'hours' => 2,
      'month' => 8,
      'day' => 1,
      'minutes' => 17,
      'year' => 2012
    };