Perl 5.18+Archive::ZIP 1.68无法递归打包NAS挂载目录文件
Perl Archive::Zip无法递归打包NAS挂载目录文件的解决思路
问题背景
升级Fedora后,使用Perl 5.18 + Archive::Zip 1.68打包NAS挂载目录时出现异常:
- 生成的ZIP文件仅保留目录结构,子目录中的文件无法被加入
- 无任何报错信息
- 将目标目录移至本地文件系统时,打包完全正常
- 命令行
zip/tar工具可正常打包NAS目录,排除权限问题
测试验证
以下两个测试脚本结果一致:
使用addDirectory的版本
use Archive::Zip qw( :ERROR_CODES :CONSTANTS ); my $zip = Archive::Zip->new(); my $dir_member = $zip->addDirectory( '/mounted_dir/to_zip/' ); unless ( $zip->writeToFileNamed('/tmp/someZip.zip') == AZ_OK ) { die 'write error'; }
使用addTree的版本
use Archive::Zip qw( :ERROR_CODES :CONSTANTS ); my $zip = Archive::Zip->new(); $zip->addTree( '/mounted_dir/to_zip/' ); unless ( $zip->writeToFileNamed('/tmp/someZip.zip') == AZ_OK ) { die 'write error'; }
解决思路与方案
1. 禁用Archive::Zip的快速遍历
Archive::Zip的addTree默认使用useFastTraversal优化,对网络文件系统(如SMB3)兼容性较差,显式禁用后改用纯Perl遍历逻辑:
use Archive::Zip qw( :ERROR_CODES :CONSTANTS ); my $zip = Archive::Zip->new(); # 第三个参数传入配置,禁用快速遍历 $zip->addTree('/mounted_dir/to_zip/', undef, { useFastTraversal => 0 }); unless ( $zip->writeToFileNamed('/tmp/someZip.zip') == AZ_OK ) { die 'write error'; }
2. 手动递归遍历并添加文件
绕过Archive::Zip的自动遍历,使用Perl核心模块File::Find手动处理每个文件/目录,兼容性更强:
use Archive::Zip qw(:ERROR_CODES :CONSTANTS); use File::Find; my $zip = Archive::Zip->new(); my $source_dir = '/mounted_dir/to_zip/'; # 递归遍历目录 find(sub { # 跳过源目录本身 return if $File::Find::name eq $source_dir; if (-f $_) { # 计算ZIP内的相对路径,去掉源目录前缀 my $zip_path = substr($File::Find::name, length($source_dir)); $zip->addFile($File::Find::name, $zip_path); } elsif (-d $_) { # 目录需添加末尾斜杠,保证ZIP内的目录结构正确 my $zip_path = substr($File::Find::name, length($source_dir)) . '/'; $zip->addDirectory($File::Find::name, $zip_path); } }, $source_dir); unless ($zip->writeToFileNamed('/tmp/someZip.zip') == AZ_OK) { die 'write error'; }
3. 降级Archive::Zip版本
由于旧环境(低版本Archive::Zip)可正常工作,可尝试降级到之前的稳定版本(如1.60):
# 使用cpanm降级,需确保已安装cpanm cpanm Archive::Zip@1.60
4. 检查文件系统挂载参数
确认NAS挂载时是否启用了特殊参数(如noacl、nobrl),部分SMB3挂载参数可能影响Perl的文件系统调用,可尝试调整挂载参数后重新测试。
内容的提问来源于stack exchange,提问作者TD_1888
相关产品推荐
相关产品推荐

