zip2tar_fast.pl 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. #!/usr/bin/perl
  2. # Author: Trizen
  3. # Date: 10 April 2024
  4. # https://github.com/trizen
  5. # Convert a ZIP archive to a TAR archive (with optional compression).
  6. # Using `zip2tarcat` from LittleUtils:
  7. # https://sourceforge.net/projects/littleutils/
  8. # Converts and recompresses a ZIP file, without storing the entire archive in memory.
  9. use 5.036;
  10. use Getopt::Long qw(GetOptions);
  11. use constant {
  12. CHUNK_SIZE => 1 << 16, # how many bytes to read per chunk
  13. };
  14. my $zip2tarcat_cmd = 'zip2tarcat'; # command to zip2tarcat
  15. sub zip2tar ($zip_file, $out_fh) {
  16. open(my $fh, '-|:raw', $zip2tarcat_cmd, $zip_file)
  17. or die "Cannot pipe into <<$zip2tarcat_cmd>>: $!";
  18. while (read($fh, (my $chunk), CHUNK_SIZE)) {
  19. $out_fh->print($chunk);
  20. }
  21. $out_fh->close;
  22. close $fh;
  23. }
  24. my $compression_method = 'none';
  25. my $keep_original = 0;
  26. my $overwrite = 0;
  27. sub usage ($exit_code) {
  28. print <<"EOT";
  29. usage: $0 [options] [zip files]
  30. options:
  31. -c --compress=s : compression method (default: $compression_method)
  32. valid: none, xz, gz, bz2, lzo, lzip, zstd
  33. -k --keep! : keep the original ZIP files (default: $keep_original)
  34. -f --force! : overwrite existing files (default: $overwrite)
  35. -h --help : print this message and exit
  36. example:
  37. # Convert a bunch of zip files to tar.xz
  38. $0 -c=xz *.zip
  39. EOT
  40. exit($exit_code);
  41. }
  42. GetOptions(
  43. 'c|compress=s' => \$compression_method,
  44. 'k|keep!' => \$keep_original,
  45. 'f|force!' => \$overwrite,
  46. 'h|help' => sub { usage(0) },
  47. )
  48. or usage(1);
  49. @ARGV || usage(2);
  50. my $tar_suffix = '';
  51. my $compression_class = undef;
  52. if ($compression_method eq 'none') {
  53. require IO::Handle;
  54. }
  55. elsif ($compression_method =~ /^(?:gz|gzip)\z/) {
  56. require IO::Compress::Gzip;
  57. $tar_suffix .= '.gz';
  58. $compression_class = 'IO::Compress::Gzip';
  59. }
  60. elsif ($compression_method =~ /^(?:bz2|bzip2)\z/) {
  61. require IO::Compress::Bzip2;
  62. $tar_suffix .= '.bz2';
  63. $compression_class = 'IO::Compress::Bzip2';
  64. }
  65. elsif ($compression_method =~ /^(?:xz)\z/) {
  66. require IO::Compress::Xz;
  67. $tar_suffix = '.xz';
  68. $compression_class = 'IO::Compress::Xz';
  69. }
  70. elsif ($compression_method =~ /^(?:lzo|lzop)\z/) {
  71. require IO::Compress::Lzop;
  72. $tar_suffix = '.lzo';
  73. $compression_class = 'IO::Compress::Lzop';
  74. }
  75. elsif ($compression_method =~ /^(?:lz|lzip)\z/) {
  76. require IO::Compress::Lzip;
  77. $tar_suffix = '.lz';
  78. $compression_class = 'IO::Compress::Lzip';
  79. }
  80. elsif ($compression_method =~ /^(?:zstandard|zstd?)\z/) {
  81. require IO::Compress::Zstd;
  82. $tar_suffix = '.zst';
  83. $compression_class = 'IO::Compress::Zstd';
  84. }
  85. else {
  86. die "Unknown compression method: <<$compression_method>>\n";
  87. }
  88. foreach my $zip_file (@ARGV) {
  89. if (-f $zip_file) {
  90. say "\n:: Processing: $zip_file";
  91. my $tar_file = ($zip_file =~ s{\.zip\z}{}ri) . '.tar' . $tar_suffix;
  92. if (-e $tar_file) {
  93. if (not $overwrite) {
  94. say "-> Tar file <<$tar_file>> already exists. Skipping...";
  95. next;
  96. }
  97. }
  98. my $out_fh;
  99. if (defined($compression_class)) {
  100. $out_fh = $compression_class->new($tar_file)
  101. or do {
  102. warn "[!] Failed to initialize the compressor: $!. Skipping...\n";
  103. next;
  104. };
  105. }
  106. else {
  107. open $out_fh, '>:raw', $tar_file
  108. or do {
  109. warn "[!] Can't create tar file <<$tar_file>>: $!\n";
  110. next;
  111. };
  112. }
  113. zip2tar($zip_file, $out_fh) || do {
  114. warn "[!] Something went wrong! Skipping...\n";
  115. unlink($tar_file);
  116. next;
  117. };
  118. my $old_size = -s $zip_file;
  119. my $new_size = -s $tar_file;
  120. say "-> $old_size vs. $new_size";
  121. if (not $keep_original) {
  122. say "-> Removing the original ZIP file: $zip_file";
  123. unlink($zip_file) or warn "[!] Can't remove file <<$zip_file>>: $!\n";
  124. }
  125. }
  126. else {
  127. warn ":: Not a file: <<$zip_file>>. Skipping...\n";
  128. }
  129. }