1

我通常是读者,但这次我找不到答案。我有一些由科学设备生成的技术文件。有时,记录的文件会损坏,我们必须手动进行一些十六进制修改。我想知道如何实现自动化。我正在考虑 Perl,因为我对此有所了解,但即使我设法读取了感兴趣的偏移量,我也不知道如何编写新值。

我有两件事要做:

  1. 在偏移量 4 处写入文件大小减 8
  2. 计算“TRCKfmt”模式的数量,即 5452434B666D74(十六进制),然后在偏移量 5C(92)处记下十六进制值。

我尝试在文件句柄上使用sysreadsyswrite,但我无法完成不同的步骤。

也许Perl不是一个好的选择,我不知道如何解决。

这是我的实际脚本:

use warnings;
use strict;
use diagnostics;

use Fcntl qw(:seek);

my($fh, $filename, $byte_position, $byte_value);

$filename      = "MYFILE.tac";
$byte_position = 4;
my $filesize = -s $filename;
    print "Size: $filesize\n";


open($fh, "<", $filename)
  || die "can't open $filename: $!";

binmode($fh)
  || die "can't binmode $filename";

sysseek($fh, $byte_position, SEEK_CUR)  # NB: 0-based
  || die "couldn't see to byte $byte_position in $filename: $!";

sysread($fh, $byte_value, 1) == 1
  || die "couldn't read byte from $filename: $!";

printf "read byte with ordinal value %#02x at position %d\n",
     ord($byte_value), $byte_position;

感谢您的任何帮助。

4

3 回答 3

1

让自己轻松一点,只需将整个文件加载到内存中。

my $qfn = "MYFILE.tac";

my $file;
{
   open(my $fh, '<:raw', $qfn)
      or die("Can't open \"$qfn\": $!\n");

   local $/;
   $file = <$fh>;
}

{
   my $packed_length = pack('N', length($file) - 8);
   substr($file, 0x0004, length($packed_length), $packed_length);
}

{
   my $num_blocks;
   ++$num_blocks while $file =~ /TRCKfmt/g;
   my $packed_num_blocks = pack('N', $num_blocks);
   substr($file, 0x005C, length($packed_num_blocks), $packed_num_blocks);
}

{
   open(my $fh, '>:raw', $qfn)
      or die("Can't create \"$qfn\": $!\n");

   print($fh $file);
}

你没有说数字应该以什么格式存储。我假设它们是大端字节顺序的 32 位无符号整数。

于 2015-06-11T17:20:16.157 回答
1

让我们创建一个充满 0 字节的文件:

C:\...\> perl -E "binmode STDOUT;say qq{\0} x 32 for 1 .. 4" > test
C:\...\> xxd 测试
00000000: 0000 0000 0000 0000 0000 0000 0000 0000 ......
00000010: 0000 0000 0000 0000 0000 0000 0000 0000 ......
00000020: 0a00 0000 0000 0000 0000 0000 0000 0000 ......
00000030: 0000 0000 0000 0000 0000 0000 0000 0000 ......
00000040: 000a 0000 0000 0000 0000 0000 0000 0000 ......
00000050: 0000 0000 0000 0000 0000 0000 0000 0000 ......
00000060: 0000 0a00 0000 0000 0000 0000 0000 0000 ......
00000070: 0000 0000 0000 0000 0000 0000 0000 0000 ......
00000080: 0000 000a ....

DATA下面的程序从该部分读取偏移量和替换字节。您可能希望将它们放在外部文件中:

#!/usr/bin/env perl

use strict;
use warnings;

use Fcntl qw(:seek);

@ARGV or die "Need filename\n";
my ($file) = @ARGV;

open my $fh, '+<:raw', $file
    or die "Cannot open '$file': $!";

while (my $edit = <DATA>) {
    next unless $edit =~ /\S/;
    my ($offset, $value) = map hex, split ' ', $edit;
    seek $fh, $offset, SEEK_SET
        or die "Failed to seek to '$offset': $!";
    print $fh chr($value)
        or die "Failed to write new byte '$value' at offset '$offset': $!";
}

close $fh
    or die "Failed to close '$file': $!";

__DATA__
0 64
8 65
10 61
18 64
20 62
28 65
30 65
38 66
40 20

运行程序后:

C:\...\> xxd 测试
00000000: 6400 0000 0000 0000 6500 0000 0000 0000 d.......e......
00000010: 6100 0000 0000 0000 6400 0000 0000 0000 a.......d.......
00000020: 6200 0000 0000 0000 6500 0000 0000 0000 b.......e......
00000030: 6500 0000 0000 0000 6600 0000 0000 0000 e.......f......
00000040: 200a 0000 0000 0000 0000 0000 0000 0000 ......
00000050: 0000 0000 0000 0000 0000 0000 0000 0000 ......
00000060: 0000 0a00 0000 0000 0000 0000 0000 0000 ......
00000070: 0000 0000 0000 0000 0000 0000 0000 0000 ......
00000080: 0000 000a ....
于 2015-06-11T18:02:44.467 回答
0

好的,感谢@ikegami,这是这个答案的回复!

#!c:/Perl64/bin/perl.exe
use warnings;
use strict;
use diagnostics;


my $dir = 'MYDIRECTORY';

opendir DIR, $dir or die "cannot open dir $dir: $!";
my @files = glob "$dir/*.tac";
closedir(DIR);

foreach(@files){
  my $qfn = $_;

my $file;
{
   open(my $fh, '<:raw', $qfn)
      or die("Can't open \"$qfn\": $!\n");

   local $/;
   $file = <$fh>;
}

{
   my $packed_length = pack('V', length($file) - 8);

   substr($file, 0x0004, length($packed_length), $packed_length);
}

{
   my $num_blocks;
   ++$num_blocks while $file =~ /TRCKfmt/g;
   my $packed_num_blocks = pack('V', $num_blocks);
   substr($file, 0x005C, length($packed_num_blocks), $packed_num_blocks);
}

{
   open(my $fh, '>:raw', $qfn)
      or die("Can't create \"$qfn\": $!\n");

   print($fh $file);
}
}

谢谢你 Stackoverflow 家伙,这真的很有帮助

于 2015-06-12T10:50:17.970 回答