求和两个文件的字节

时间:2016-01-11 10:24:29

标签: perl

我想获取a文件的每个字节并将第二个文件的相应字节添加到其中。我想输出结果的十六进制。

例如:

$ od -t x1 file1
0000000 78
0000001

$ od -t x1 file2
0000000 78
0000001

$ cat desired_output.txt
F0

我的代码目前将每个单个字符加总,就像在我的例子中一样:

  

7 + 7 = E8 + 8 = 10

而不是

  

78 + 78 = F0

这是我的代码。

use warnings 'all';
use strict;
use autodie;

{
    my $input = do {
        open my $in, '<', $ARGV[0];
        local $/;
        <$in>
    };

    open my $out, '>', 'hex.txt';
    print $out unpack 'H*', $input;
}

{
    my $input = do {
        open my $in, '<', $ARGV[1];
        local $/;
        <$in>
    };

    open my $out, '>', 'hex2.txt';
    print $out unpack 'H*', $input;
}

open my $fh1, '<', 'hex.txt';
open my $fh2, '<', 'hex2.txt';

until ( eof $fh1 or eof $fh2 ) {

    my @l1 = map hex, split //, <$fh1>;
    my @l2 = map hex, split //, <$fh2>;

    my $n = @l2 > @l1 ? @l2 : @l1;

    my @sum = map {

        $l1[$_] + $l2[$_];
    } 0 .. $n-1;

    @sum = map { sprintf '%X', $_ } @sum;

    open my $out, '>', 'out.txt';
    print { $out } @sum, "\n";
}

4 个答案:

答案 0 :(得分:2)

您的问题是,您正在使用split //逐行阅读文件,这会为您提供每个字符,但您需要两个。 split无法做到这一点。

您可以使用文件中的read to grab two bytes at a time。那些你可以使用hex转换为十进制的那些。我使用List::MoreUtils' pairwise来简化它。

use strict;
use warnings;
use List::MoreUtils 'pairwise';
use Data::Dumper;

my @l1;
my @l2 = (78, 79, 80);
until (eof \*DATA) {
    read \*DATA, my $chars, 2;
    push @l1, $chars;
}


# sum them up
my @sums = map { sprintf '%X', $_ } pairwise {  hex($a) + hex($b) } @l1, @l2;
print Dumper \@sums;

__DATA__
787878

答案 1 :(得分:1)

自己找到解决方案。我用过:

open my $fh1, '<', 'hex.txt';
open my $fh2, '<', 'hex2.txt';

until ( eof $fh1 or eof $fh2 ) {


    my @l1 = map hex,unpack '(a2)*', <$fh1>;
    my @l2 = map hex,unpack '(a2)*', <$fh2>;

    my $n = @l2 > @l1 ? @l2 : @l1;

    my @sum = map {

        $l1[$_] + $l2[$_];
    } 0 .. $n-1;

    @sum = map { sprintf '%X', $_ } @sum;

    open my $out, '>', 'sum.txt';
    print { $out } @sum, "\n";
}

答案 2 :(得分:0)

映射到十六进制然后添加会导致您描述的行为。不要这样做。首先将字符值添加为整数,然后将结果整数转换为十六进制字符串。

printf "%X\n", ord("x") + ord("x");

循环输入文件,并假设(根据评论)文件总是相同的长度,可能像

$/ = undef;
open my $input1, '<', $ARGV[0] or die "Could not open $ARGV[0]: $!";
my $str1 = <$input1>;
close($input1);  # Don't forget to close()!
open my $input2, '<', $ARGV[1] or die "Could not open $ARGV[1]: $!";
my $str2 = <$input2>;
close($input2);
@sums = ();
for (my $i=0; $i < $#input1; ++$i) {
    push @sums, ord(substr($input1, $i, 1)) + ord(substr($input2, $i, 1));
}

将输入文件的十六进制表示复制到每个输出文件的单独输出文件中似乎不是您的问题的核心,因此留作(微不足道)练习。

答案 3 :(得分:0)

十六进制是数字的文本表示。要添加两个十六进制字符串表示的数字,必须先将它们转换为数字(例如,使用hex)。

但是你为什么要转换为十六进制呢?而不是字节⇒十六进制数,以下字节⇒num直接执行。

use strict;
use warnings 'all';
use autodie;

my $file1 = do {
   open my $fh, '<:raw', $ARGV[0];
   local $/;
   <$fh>
};

my $file2 = do {
   open my $fh, '<:raw', $ARGV[1];
   local $/;
   <$fh>
};

my @l1 = unpack('C*', $file1);
my @l2 = unpack('C*', $file2);

my $n = @l2 > @l1 ? @l2 : @l1;
my @sums = map { $l1[$_] + $l2[$_] } 0..$n-1;

my $file_out = pack('C*', @sums);   # This is probably what you actually want in your file
print unpack('H*', $file_out);      # But this is what you said you wanted.