Perl 重命名文件时在存档中找不到文件

Perl 重命名文件时在存档中找不到文件,perl,Perl,该程序从命令行上指定的目录中读取文件列表,创建哈希数组,其中每个文件都有密钥路径、大小和sha256sum 我试图创建一个gzip文件tarball,其中每个文件的名称都是附加了文件原始扩展名的校验和 我成功地创建了一个gzip文件tarball。但是,当我尝试使用Archive::Tar的重命名方法时,遇到以下错误: 存档文件中没有此类文件:“/path/to/file1.txt”,位于./program.pl第62行。存档中的每个文件都会重复此错误 use strict; use warni

该程序从命令行上指定的目录中读取文件列表,创建哈希数组,其中每个文件都有密钥路径、大小和sha256sum

我试图创建一个gzip文件tarball,其中每个文件的名称都是附加了文件原始扩展名的校验和

我成功地创建了一个gzip文件tarball。但是,当我尝试使用Archive::Tar的重命名方法时,遇到以下错误:

存档文件中没有此类文件:“/path/to/file1.txt”,位于./program.pl第62行。存档中的每个文件都会重复此错误

use strict;
use warnings;
use Data::Dumper qw(Dumper);
use File::Spec qw(catfile rel2abs);
use Digest::SHA qw(sha256_hex);
use Archive::Tar;
use Archive::Tar::File;

my $dir = $ARGV[0];
my $url = $ARGV[1];
my @AoH;
my @checksumfiles;
my $tar = Archive::Tar->new;
my $archive = "archive.tar.gz";

opendir DIR, $dir or die "cannot open dir $dir: $!\n";
chdir $dir or die "cannot navigate to dir $dir: $!\n";

while(my $file = readdir DIR) {
    next unless(-f File::Spec->catfile($dir, $file));
    next if($file =~ m/^\./);

    my $fullpath = File::Spec->rel2abs($file);
    my $fullsize = -s File::Spec->catfile($dir, $file);
    my $fullid   = sha256_hex($fullpath);

    my %hash = (
        path    =>  $fullpath,
        size    =>  $fullsize,
        id      =>  $fullid,
    );

    push(@AoH, \%hash);
}
my @array;
for my $i(0..$#AoH) {
    no warnings 'uninitialized';
    my ($ext) = $AoH[$i]{path} =~ (/(\.[^.]+)$/);
    my $idext = $AoH[$i]{id} . $ext;
    push(@checksumfiles, $idext);
    push(@array, $AoH[$i]{path});
}

Archive::Tar->create_archive($archive, COMPRESS_GZIP, @array);
#print Archive::Tar->list_archive($archive, COMPRESS_GZIP), "\n";

for my $i(0..$#array) {
    $tar->rename($array[$i], $checksumfiles[$i]);
}

print Dumper sort \@array;
print Dumper sort \@checksumfiles;
#print Dumper sort \@AoH;

归档文件是用Class方法创建的,而该方法是在对象上调用的(我的重点)

将内存中的存档文件重命名为$new\u name

唉,由于该对象从未用于写入/读取归档文件,因此内存中没有归档文件

通常,您可以将归档文件从磁盘读入内存,从中获取对象。然后重命名这些文件并写出一个新的归档文件

my @file_objs = $tar->read($archive);

for my $i (0..$#file_objs) {
    $file_objs[$i]->rename($checksumfiles[$i]);
}
$tar->write('RENAMED_' . $archive, COMPRESS_GZIP);
这在我的测试中奏效了

但是,如果您确实是首先创建归档文件,并进行额外的写入和读取,那么这将是非常浪费的。在内存中构建存档的合适方法是

文件的重命名顺序与添加顺序相同,因此所有文件都必须确实已添加,否则我们可能会以错误的名称结束。因此,如果在添加文件时出现任何错误,我们都会中止。这就是为什么这也需要在子文件中,这样更改就不会滑入,从而导致重命名文件的顺序混乱

如果这在模块中结束,请使用:
carp
而不是
warn
。如果主代码不应在出现错误时继续执行,请使用模块中的
die
(或
Carp::croak


如果此方法的文档中提到的特定属性出现问题(它们不应该出现),您甚至可以先用新名称复制文件,然后用这些名称形成存档(然后删除它们)。这也是额外的工作,但比额外的阅读和写作档案更有效。

交叉点:()请提及交叉点来拯救人们的工作。你会考虑其他方法吗?这是我第一次使用文件压缩进行编程。@如果存档文件不存在,JonathanDewein会以更好的方式进行更新(您甚至可以先复制具有新名称的文件)。谢谢你的署名。
# In a sub to make sure that renaming stays in order in which files are added
sub archive_renamed {
    my ($archive_name, $orig, $new) = @_;
    if (@$orig != @$new) {
        warn "Unequal length of filename lists";
        return;
    }
    my $tar = Archive::Tar->new;

    for my $file (@$orig) {
        if (not $tar->add_files($file)) {
            warn "Error adding $file: ", $tar->error;             
            return;
        }
    }
    my @file_objs = $tar->get_files;

    for my $i (0..$#file_objs) {
        $file_objs[$i]->rename($new->[$i]);
    }

    $tar->write($archive_name, COMPRESS_GZIP);
    if (my $error = $tar->error) {
        warn "Error writing $archive_name: $error";
        return;
    }
    return 1;
}

archive_renamed('RENAMED_'.$archive, \@array, \@checksumfiles);