■Windows版Perlの細道・けもの道

■ナビゲータ

[南北館(最初のメニュー)]

  1. [Windows版Perlの細道・けもの道]
    1. [1.準備編]
    2. [2.基本編]
    3. [3.応用編]
      1. [3-1.固定長データとCSVデータとの変換]
      2. [3-2.重複データの処理]
      3. [3-3.フォルダ内の一括処理]
        1. [3-3-1.フォルダ内のファイル名を出力する]
        2. [3-3-2.フォルダ内の複数のファイルをまとめて、1つのファイルに出力する]
        3. [3-3-3.フォルダ内のファイルについて一括変更をする]
      4. [3-4.1つのファイルを複数のファイルに分割する]
      5. [3-5.文字コードの変換]
      6. [3-6.半角全角変換]
      7. [3-7.多次元配列の処理]
      8. [3-9.その他]
    4. [スクリプトと入力データのサンプル]
rubyではどう処理する?
同じことをrubyではこうしています。

3.応用編

3-3.フォルダ内の一括処理

3-3-1.フォルダ内のファイル名を出力する

フォルダ(ディレクトリ)操作を行うには、「ディレクトリ操作関数」を利用します。ここでは、ディレクトリをオープンする「opendir」関数、ディレクトリ内のファイル名を読み出す「readdir」関数、ディレクトリをクローズする「closedir」関数を利用しています。

まず、フォルダは「opendir」関数でオープンします。引数はファイルハンドルとディレクトリですが、ディレクトリの「\」記号は「/」に変更します。したがって「c:\Perl64\html\」というフォルダは、「c:/Perl64/html/」と指定します。また、通常の入力ファイルであれば、「<IN1>」のように指定する部分は、「reddir(IN1)」と指定します。

「readdir」関数は、フォルダ内のファイルの他に、サブディレクトリや自分自身である「.」や親ディレクトリである「..」を出力します。このうち、ディレクトリ以外の通常のファイルだけを判定するためにPerlには「ファイルテスト演算子」があります。

「ファイルテスト演算子」は、「if -f ファイル名の変数」の形式で通常のファイルかどうかが判定できます。「ファイル名の変数」には、ドライブ名も含めたフルパスでファイル名を指定する必要があります。「readdir」関数で呼び出したファイル名と変数「$path」に入れておいたパス名を連結し、フルパスにしてから、「ファイルテスト演算子」を利用しているのは、このためです。ここでも「\」記号は「/」に変更しておきます。

なお、フォルダ名やファイル名にアクセント記号のついた半角アルファベットなどが含まれていると、正常に出力されない場合がありますので、注意してください

実際に応用する場合は、入出力データのファイル名等変更して利用します。

【スクリプト】
# readdir.pl    
# 内容 : フォルダ内のファイル名を出力  
# Copyright (c) 2002-2013 Mitsuo Minagawa, All rights reserved. 
# (minagawa@fb3.so-net.ne.jp)   
# 使用方法 : c:\>perl readdir.pl    
#   
$path   =   "c:/Perl64/html/";
opendir(IN1,$path); 
open(OUT1,">filename.txt"); 
while   ($filename  =   readdir(IN1))   {       
    print   OUT1    $filename,"\n"  if  -f  $path.$filename;    
}   
closedir(IN1);
close(OUT1);
    
【スクリプトとデータのサンプル】

スクリプトはこちらにあります。

【スクリプトの解説】

ファイルの出力

    print   OUT1    $filename,"\n"  if  -f  $path.$filename;
   

$pathと$filenameを連結することでフルパスのファイル名になります。通常のファイルかどうかの判定はフルパスで行いますので、「if -f $path.$filename;」で判定します。特定の拡張子のファイル名だけにしたい場合は、以下のようにします(以下は拡張子が"html"の場合です)。

    if      ($filename  =~  /\.html/)       {
            print   OUT1    $filename,"\n";
    }
   
【出力データ】
Active.css
activeperl.html
Artistic.txt
blank.html
changes.html
Copyright.html
displayToc.js
EULA-Community_License.rtf
EULA-Community_License.txt
favicon.ico
index.html
install.html
perlmain.html
perltoc.html
readme.html
release.html
resources.html
scineplex.css
tocHeader.css
tocParas.js
tocTab.js
topframe.html
    
【出力データ】(「if -f $path」の条件がない場合)
.
..
Active.css
activeperl.html
Artistic.txt
bin
blank.html
changes.html
Components
Copyright.html
displayToc.js
EULA-Community_License.rtf
EULA-Community_License.txt
faq
favicon.ico
images
index.html
install.html
lib
perlmain.html
perltoc.html
readme.html
release.html
resources.html
scineplex.css
site
tocHeader.css
tocParas.js
tocTab.js
topframe.html
Windows
    



上記は特定のフォルダだけを対象にしたものですが、フォルダの中にサブフォルダが存在する場合、サブフォルダの配下にあるファイルも含めたファイル名を出力するスクリプトは以下のようになります。

サブフォルダの配下にあるファイルも含めたファイル名を出力しますので、「再帰処理」を行います。再帰処理でのポイントはローカル変数を適切に使用することです。ローカル変数は「my」宣言で指定できます。

下記の例では、"c:\Perl64\html\"のフォルダにあるファイルをサブフォルダも含めて、出力しています。実際に応用する場合は、入出力データのファイル名等変更して利用します。

【スクリプト】
# readdir2.pl   
# 内容 : フォルダ内のファイル名を出力  
#     (サブフォルダ内もすべて出力)  
# Copyright (c) 2013 Mitsuo Minagawa, All rights reserved.  
# (minagawa@fb3.so-net.ne.jp)   
# 使用方法 : c:\>perl readdir2.pl   
#   

$dir    =   "c:/Perl64/html/";  
open(OUT1,">temp.txt"); 

file_name($dir);    

sub file_name()             {   
    my  ($dir)  =   @_; 
    opendir(IN1,$dir);  
    my  @filename   =   readdir(IN1);   
    my  $i; 
    for     ($i =   0;  $i  <=  $#filename; $i++)   {       
# フォルダ以外の場合    
        if      (-f $dir.$filename[$i])         {   
                $out1   =   join("\t",$filename[$i],$dir);  
                print   OUT1    "$out1\n";      
        }   
# フォルダの場合(カレントフォルダと親フォルダを除く)    
        elsif   (($filename[$i] ne  ".")    
            &&  ($filename[$i]  ne  ".."))      {   
                my  $sv_dir =   $dir;   
                $dir    =   $dir.$filename[$i]."/"; 
# サブフォルダ内の処理  
                file_name($dir);    
# カレントフォルダに戻る    
                $dir    =   $sv_dir;    
        }   
    }   
}   

closedir(IN1);  
close(OUT1);    

#       
open(IN1,"temp.txt");       
open(OUT1,">filename.txt");     

# ソートキーの入っている項目番号    
@sortkey    =   (1,0);  
# ソートキーをセットするハッシュのキー  
$key    =   undef;  
# ソート用のキーと1行分レコードをセットするハッシュ 
%sort_record    =   (); 
# 入力ファイルを全部読み込む。  
@record =   <IN1>;      
# ソートキーとなる項目番号からソートキーとなる文字列を作っておく。  
#recno番目のレコードがrecordである。    
foreach $recno  (0..$#record)   {   
    chomp($record[$recno]); 
# 入力ファイルをタブで分解する。    
    @in1    =   split("\t",$record[$recno],-1); 
# ソートキーとなる項目の内容をタブで連結してハッシュのキーとする。  
    foreach $sortno (@sortkey)  {       
        $key    .=  lc($in1[$sortno]) . "\t";   
    }       
# 同じ値を持つキーが複数存在する場合に以下のように指定する。    
    $key    .=  sprintf("%08d",$recno); 
# レコードをハッシュの値としてセットする。  
    $sort_record{$key}  =   $record[$recno];    
    $key    =   undef;  
}   
# ハッシュのキーをソートし、キー順にレコードを出力する。    
foreach $recno  (sort   keys    %sort_record)   {   
        print   OUT1    "$sort_record{$recno}\n";   
}   
close(IN1); 
close(OUT1);    
    
【スクリプトとデータのサンプル】

スクリプトはこちらにあります。

【スクリプトの解説】

フォルダの指定

$dir    =   "c:/Perl64/html/";  
file_name($dir);    
   

$dirには出力するフォルダをドライブ名も含めて、指定します。ただし「\」は「/」に変えます。そして、$dirを引数にして、サブプログラムを呼び出します。

サブプログラムの初期値設定

sub file_name()             {   
    my  ($dir)  =   @_; 
    opendir(IN1,$dir);  
    my  @filename   =   readdir(IN1);
   

サブプログラムの内部では、引数「@_」をmy宣言をした変数にセットします。これにより、サブプログラム内部で変更した結果は呼び出したときの引数に影響を与えずに使用できるようになります。左辺の「my ($dir)」はリストである点に注意してください。「my $dir」とすると引数の個数である"1"がセットされてしまいます。また、右辺に「readdir」関数、左辺に配列変数を置くと、「readdir」関数で取得したファイル名がすべて、「@filename」に一度にセットされます。

ファイル名出力

    for     ($i =   0;  $i  <=  $#filename; $i++)   {       
# フォルダ以外の場合    
        if      (-f $dir.$filename[$i])         {   
                $out1   =   join("\t",$filename[$i],$dir);  
                print   OUT1    "$out1\n";      
        }   
# フォルダの場合(カレントフォルダと親フォルダを除く)    
        elsif   (($filename[$i] ne  ".")    
            &&  ($filename[$i]  ne  ".."))      {   
                my  $sv_dir =   $dir;   
                $dir    =   $dir.$filename[$i]."/"; 
# サブフォルダ内の処理  
                file_name($dir);    
# カレントフォルダに戻る    
                $dir    =   $sv_dir;    
        }   
    }   
   

フォルダ内で通常のファイル(サブフォルダ以外)であれば、ファイル名とフォルダ名をあわせて出力します。また、サブフォルダの場合はカレントフォルダと親フォルダを除いて、再帰処理でサブフォルダ内の処理を行います。

再帰処理を行う場合は、カレントフォルダ名をmy宣言をした変数に保存します。これにより、サブフォルダ内の処理を終わった後、元のフォルダの処理が続行できるようになります。

ファイル名の並べ替え

open(IN1,"temp.txt");       
open(OUT1,">filename.txt");     

# ソートキーの入っている項目番号    
@sortkey    =   (1,0);  
# ソートキーをセットするハッシュのキー  
$key    =   undef;  
# ソート用のキーと1行分レコードをセットするハッシュ 
%sort_record    =   (); 
# 入力ファイルを全部読み込む。  
@record =   <IN1>;      
# ソートキーとなる項目番号からソートキーとなる文字列を作っておく。  
#recno番目のレコードがrecordである。    
foreach $recno  (0..$#record)   {   
    chomp($record[$recno]); 
# 入力ファイルをタブで分解する。    
    @in1    =   split("\t",$record[$recno],-1); 
# ソートキーとなる項目の内容をタブで連結してハッシュのキーとする。  
    foreach $sortno (@sortkey)  {       
        $key    .=  lc($in1[$sortno]) . "\t";   
    }       
# 同じ値を持つキーが複数存在する場合に以下のように指定する。    
    $key    .=  sprintf("%08d",$recno); 
# レコードをハッシュの値としてセットする。  
    $sort_record{$key}  =   $record[$recno];    
    $key    =   undef;  
}   
# ハッシュのキーをソートし、キー順にレコードを出力する。    
foreach $recno  (sort   keys    %sort_record)   {   
        print   OUT1    "$sort_record{$recno}\n";   
}   
close(IN1); 
close(OUT1);    
   

出力したファイルをフォルダ名順のファイル名順で並べ替えています。ドライブ名とフォルダ名つきのファイル名を出力したい場合は、出力する箇所を以下のように変更します。

# ハッシュのキーをソートし、キー順にレコードを出力する。    
foreach $recno  (sort   keys    %sort_record)   {   
        @temp   =   split("\t",$sort_record{$recno});
        $out1   =   $temp[1].$temp[0];
        print   OUT1    "$out1\n";
}   
   
【出力データ】
Active.css  c:/Perl64/html/
activeperl.html c:/Perl64/html/
Artistic.txt    c:/Perl64/html/
blank.html  c:/Perl64/html/
changes.html    c:/Perl64/html/
Copyright.html  c:/Perl64/html/
displayToc.js	c:/Perl64/html/
EULA-Community_License.rtf  c:/Perl64/html/
EULA-Community_License.txt  c:/Perl64/html/
favicon.ico c:/Perl64/html/
index.html  c:/Perl64/html/
install.html    c:/Perl64/html/
perlmain.html   c:/Perl64/html/
perltoc.html    c:/Perl64/html/
readme.html c:/Perl64/html/
release.html    c:/Perl64/html/
resources.html  c:/Perl64/html/
scineplex.css   c:/Perl64/html/
tocHeader.css   c:/Perl64/html/
tocParas.js c:/Perl64/html/
tocTab.js   c:/Perl64/html/
topframe.html   c:/Perl64/html/
ap-iis-config.html  c:/Perl64/html/bin/
ap-update-html.html c:/Perl64/html/bin/
ap-user-guide.html  c:/Perl64/html/bin/
c2ph.html   c:/Perl64/html/bin/
・・・・・<以下略>
    
【出力データ(ドライブ名とフォルダ名つきのファイル名にしたとき)】
c:/Perl64/html/Active.css
c:/Perl64/html/activeperl.html
c:/Perl64/html/Artistic.txt
c:/Perl64/html/blank.html
c:/Perl64/html/changes.html
c:/Perl64/html/Copyright.html
c:/Perl64/html/displayToc.js
c:/Perl64/html/EULA-Community_License.rtf
c:/Perl64/html/EULA-Community_License.txt
c:/Perl64/html/favicon.ico
c:/Perl64/html/index.html
c:/Perl64/html/install.html
c:/Perl64/html/perlmain.html
c:/Perl64/html/perltoc.html
c:/Perl64/html/readme.html
c:/Perl64/html/release.html
c:/Perl64/html/resources.html
c:/Perl64/html/scineplex.css
c:/Perl64/html/tocHeader.css
c:/Perl64/html/tocParas.js
c:/Perl64/html/tocTab.js
c:/Perl64/html/topframe.html
c:/Perl64/html/bin/ap-iis-config.html
c:/Perl64/html/bin/ap-update-html.html
c:/Perl64/html/bin/ap-user-guide.html
c:/Perl64/html/bin/c2ph.html
・・・・・<以下略>
    



Copyright (c) 2004-2013 Mitsuo Minagawa, All rights reserved.