此程序从命令行上指定的目录中读取文件列表,创建了一系列哈希,每个文件都有密钥路径,大小和sha256sum。
我正在尝试创建一个文件的gzp tarball,其中每个文件都名称为文件的原始扩展名。
我成功地创建了文件的tarball。但是,当我尝试使用Archive :: Tar的重命名方法时,我会遇到此错误:
在存档中没有此类文件:'/path/to/file1.txt'at ./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方法 create_archive
创建档案
重命名 in-memory 存档到$ new_name。
a,由于该对象从未用来编写/读取存档,因此没有内存档案。
通常,您可以从磁盘到内存中读取一个存档,并在其中获取存档:: tar ::文件对象。然后重命名文件并写出新的存档。
my @file_objs = $tar->read($archive);
for my $i (0..$#file_objs) {
$file_objs[$i]->rename($checksumfiles[$i]);
}
$tar->write('RENAMED_' . $archive, COMPRESS_GZIP);
这在我的测试中起作用。
但是,如果您确实首先创建档案,那么这是非常浪费的,并有额外的写入和阅读。构建存档中内存的一种合适方法是add_files
# 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);
文件以与添加的顺序相同的顺序重命名,因此必须确实添加了所有文件,否则我们可以最终以错误名称。因此,我们在添加文件中删除任何错误。这就是为什么它也需要在子中,以便更改不能滑入以便最终将文件重命名。
如果这最终以模块的形式使用Carp :: carp
而不是warn
。如果主代码不应在错误上进行,则使用die
(或模块中的Carp::croak
)。
如果此方法中提到的文档中提到的特定属性提出了一个问题(它们不应该),则您甚至可以首先复制使用新名称的文件并与这些文件一起形成存档(然后删除它们)。这也是额外的工作,但比额外的阅读和档案撰写更有效的效率。