読者です 読者をやめる 読者になる 読者になる

zipを扱うスクリプトメモ

複数の画像があるフォルダを圧縮してできたzipファイルを扱うスクリプトに関するメモです。

Archive::Zip

zipファイルの操作は、Archive::Zipモジュールを使用します。

use strict;
use warnings;
use Archive::Zip;

my $zip_path = $ARGV[0];

my $m_zip = Archive::Zip->new();
$m_zip->read($zip_path);

# zipの中にあるファイル名のリストを取得する
my @member = $m_zip->members();
foreach my $m (@members) {
   my $file_name = $m->fileName();
   print $file_name, "\n";
}


# zipの中にある画像ファイルのみを取り出してくる
my $save_path = './';
foreach my $m (@members) {
   my $file_name = $m->fileName();
   if ($file_name =~ /\.(jpg|jpeg|gif|png)$/) {
      $m_zip->extractMemberWithoutPaths($file_name, $save_path.$file_name);
   }
}

日本語の扱い

ファイル名が日本語になっている場合があるので、zipファイルで使われている文字コードを推測して変換するようにします。
文字コードの変換にはEncodeモジュール、
文字コードの推測にはEncode::Guessモジュールを使用します。文字列の長さなどによっては推測できないかもしれません。推測できなかった場合は「cp932」として扱うようにしてしまいました。
使用しているOSはMacなので最終的にUTF8に直します。

use strict;
use warnings;
use Encode;
use Encode::Guess qw/euc-jp shiftjis 7bit-jis/;

sub guess_and_convert {
   my $str = shift;

   my $guess = Encode::Guess::guess_encoding($str);
   if (ref($guess) && $guess->name) {
      $str = encode('utf8',decode($guess->name,$str));
   } else {
      $str = encode('utf8',decode('cp932',$str));
   }
   
   return $str;
}


ということで、この関数を使い、ファイル表示部分と書き込み部分で変換を行なうように先ほどのプログラムを改修しました。

use strict;
use warnings;
use Encode;
use Encode::Guess qw/euc-jp shiftjis 7bit-jis/;
use Archive::Zip;

my $zip_path = $ARGV[0];

my $m_zip = Archive::Zip->new();
$m_zip->read($zip_path);

my @members = $m_zip->members();
foreach my $m (@members) {
    my $file_name = $m->fileName();
    $file_name = guess_and_convert($file_name);
    print $file_name, "\n";
}

my $save_path = './';
foreach my $m (@members) {
    my $file_name = $m->fileName();
    if ($file_name =~ /\.(jpg|jpeg|gif|png)$/) {
        my $file_name_utf8 = guess_and_convert($file_name);
        $m_zip->extractMemberWithoutPaths($file_name,$save_path.$file_name_utf8\
);
    }
}

CGIとの連携

ブラウザからzipファイルを操作する時は、URI::Escapeモジュールでファイル名を扱う方がいいかもしれないと考えています。