【Perl】ファイル名に日本語が含まれる場合の処理

公開:
更新:

Perlでファイル名に日本語が含まれる場合の処理でハマったので対応方法をメモしておく。

サンプルコード

環境はWindows、言語はPerl、ファイル名は”fileopen.pl”、ファイルのエンコードは”utf8″。対象フォルダにある、ファイル名が”日本語”で始まるファイルを探して、その中身を表示するコードです。

#!/usr/local/bin/perl

# -*- Encoding: UTF-8 -*-

use strict;
use warnings;

use utf8;

use IO::Dir;
use IO::File;

binmode STDIN,  ":encoding(cp932)";
binmode STDOUT, ":encoding(cp932)";
binmode STDERR, ":encoding(cp932)";

my $target_dir = './';
my $prefix     = '日本語';

my $dir = IO::Dir->new($target_dir) or die $!;

if ( defined $dir ) {
    while ( my $file = $dir->read ) {
        next if $file =~ /^\./;

        print "対象フォルダ\"$target_dir\"に[$file]というファイルが見つかりました.\n";

        if ( $file =~ /^$prefix/ ) {
            print "[$file]はファイル名が\"$prefix\"で始まるので中身を表示します.\n";

            my $fh = IO::File->new( "$target_dir$file", '<:encoding(cp932)' )
              or die $!;

            print "-- ここから --\n";

            while ( my $line = $fh->getline ) {
                print $line;
            }

            print "\n-- ここまで --\n";

            $fh->close;
        }
    }
}

exit;

__END__

開きたいファイルは”日本語のファイル名.txt”、ファイルのエンコードは”cp932″です。中身は「あいうえお」。

あ
い
う
え
お

このまま実行すると下のようになる。

C:\home\perl\> perl .\fileopen.pl
対象フォルダ"./"に[fileopen.pl]というファイルが見つかりました.
"\x{0093}" does not map to cp932 at .\fileopen.pl line 26.
"\x{0096}" does not map to cp932 at .\fileopen.pl line 26.
"\x{008c}" does not map to cp932 at .\fileopen.pl line 26.
"\x{0082}" does not map to cp932 at .\fileopen.pl line 26.
"\x{0083}" does not map to cp932 at .\fileopen.pl line 26.
"\x{0083}" does not map to cp932 at .\fileopen.pl line 26.
"\x{0083}" does not map to cp932 at .\fileopen.pl line 26.
"\x{0083}" does not map to cp932 at .\fileopen.pl line 26.
"\x{008b}" does not map to cp932 at .\fileopen.pl line 26.
"\x{0096}" does not map to cp932 at .\fileopen.pl line 26.
"\x{00bc}" does not map to cp932 at .\fileopen.pl line 26.
対象フォルダ"./"に[\x{0093}u\x{0096}{\x{008c}e\x{0082}I\x{0083}t\x{0083}@\x{0083}C\x{0083}\x{008b}\x{0096}\x{00bc}.txt]というファイルが見つかりました.

デコードして文字化けを回避する

日本語が含まれるファイル名に対して何かしら処理をする前にデコードしておかないといけない。「$file = decode( ‘cp932’, $file );」のようにファイル名をデコードする命令を追加する。decode関数を使うために「use Encode qw(decode);」も追加してモジュールをロードする。

C:\home\perl\> perl .\fileopen.pl
対象フォルダ"./"に[fileopen.pl]というファイルが見つかりました.
対象フォルダ"./"に[日本語のファイル名.txt]というファイルが見つかりました.
[日本語のファイル名.txt]はファイル名が"日本語"で始まるので中身を表示します.
No such file or directory at .\fileopen.pl line 34.

とりあえず文字化けはしなくなった。

エンコードしてファイルを開く

ファイルをオープンする前にエンコードしないといけなかった。「$file = encode( ‘cp932’, $file );」のようにファイル名をエンコードする命令を追加する。encode関数を使うために「use Encode qw(decode encode);」のようにuse文を変更する。

C:\home\perl\> perl .\fileopen.pl
対象フォルダ"./"に[fileopen.pl]というファイルが見つかりました.
対象フォルダ"./"に[日本語のファイル名.txt]というファイルが見つかりました.
[日本語のファイル名.txt]はファイル名が"日本語"で始まるので中身を表示します.
-- ここから --
あ
い
う
え
お
-- ここまで --

目的通りの動きをしてくれるようになりました。最終的なコードは下記のとおり。

#!/usr/local/bin/perl

# -*- Encoding: UTF-8 -*-

use strict;
use warnings;

use utf8;
use Encode qw(decode encode);

use IO::Dir;
use IO::File;

binmode STDIN,  ":encoding(cp932)";
binmode STDOUT, ":encoding(cp932)";
binmode STDERR, ":encoding(cp932)";

my $target_dir = './';
my $prefix     = '日本語';

my $dir = IO::Dir->new($target_dir) or die $!;

if ( defined $dir ) {
    while ( my $file = $dir->read ) {
        next if $file =~ /^\./;

        $file = decode( 'cp932', $file );

        print "対象フォルダ\"$target_dir\"に[$file]というファイルが見つかりました.\n";

        if ( $file =~ /^$prefix/ ) {
            print "[$file]はファイル名が\"$prefix\"で始まるので中身を表示します.\n";

            $file = encode( 'cp932', $file );

            my $fh = IO::File->new( "$target_dir$file", '<:encoding(cp932)' )
              or die $!;

            print "-- ここから --\n";

            while ( my $line = $fh->getline ) {
                print $line;
            }

            print "\n-- ここまで --\n";

            $fh->close;
        }
    }
}

exit;

__END__

過去の同じ日の記事一覧