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

■ナビゲータ

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

  1. [Windows版Rubyの細道・けもの道]
    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. [スクリプトと入力データのサンプル]
Perlではどう処理する?
同じことをPerlではこうしています。

3.応用編

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

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

フォルダ(ディレクトリ)操作を行うには、「Dirクラス」を利用します。Perlのように「opendir」関数や「readdir」関数ではなく、Dirオブジェクトのメソッドとして、「openメソッド」や「eachメソッド」などを利用することになります。

まず、フォルダは「openメソッド」でオープンします。引数はディレクトリですが、ディレクトリの「\」記号は「/」に変更します。したがって、

    c:\Ruby\doc\ruby\ruby-1.9.1\ 
   

というフォルダは、

    c:/ruby/doc/ruby/ruby-1.9.1/ 
   

と指定します。openメソッドによって、一度に変数にセットされるため、1件ずつ処理するには、「eachメソッド」を利用します。

Dirオブジェクトの「openメソッド」は、フォルダ内のファイルの他に、サブディレクトリや自分自身である「.」や親ディレクトリである「..」を出力します。このうち、ディレクトリ以外の通常のファイルだけを判定するためにRubyには「FileTestモジュール」があります。「FileTestモジュール」は、

    FileTest.file?(ファイル名)
   

の形式でファイル(フォルダを除く)かどうかが判定できます。判定する場合は、フルパスでファイル名を指定する必要があるので、「$dir_name」に初期値としてフォルダ名をセットしておいたものをつけて、指定します。

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

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

【スクリプト】
# readdir.rb    
# 内容 : フォルダ内のファイル名出力    
# Copyright (c) 2002-2015 Mitsuo Minagawa, All rights reserved. 
# (minagawa@fb3.so-net.ne.jp)   
# 使用方法 : c:\>ruby readdir.rb    
#   
# ファイル名を出力するフォルダ  
dir_name    =   "c:/ruby19/doc/ruby/ruby-1.9.1/"    
filename    =   Dir.open(dir_name)  
# 出力ファイル  
out1_file   =   open("filename.txt","w")    

# 主処理    
filename.each   { |name|    
    fullname    =   dir_name + name 
    if      (FileTest.file?(fullname))  
            out1_file.print name,"\n"   
    elsif   (FileTest.directory?(fullname)) 
            out1_file.print name,"\n"   
    end     
}   

# ファイルのクローズ    
out1_file.close 
   
【スクリプトとデータのサンプル】

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

【スクリプトの解説】

ファイルの出力

    fullname    =   dir_name + name 
    if      (FileTest.file?(fullname))      
            out1_file.print name,"\n"       
    elsif   (FileTest.directory?(fullname))     
            out1_file.print name,"\n"       
    end     
   

「fullname = dir_name + name」とすることで、ドライブ名やフォルダ名のついたファイル名になります。こうしたファイル名にすることで、「if (FileTest.file?(fullname))」によって通常のファイルかどうかが判定できます。また、フォルダ(ディレクトリ)かどうかを判定するには「elsif (FileTest.directory?(fullname))」で判定できます。特定の拡張子のファイル名だけにしたい場合は、以下のようにします(以下は拡張子が"html"の場合です)。

    if      (/\.html/   =~  name)
            out1_file.print    name,"\n"    
    end    
   

また、フォルダ名やファイル名に全角文字を含む場合は、$KCODEやマジックコメントを使います。詳しくは[2-1-5.スクリプトの中で漢字を使う]を参照してください。

【出力データ】
ChangeLog
COPYING
COPYING.ja
GPL
LEGAL
LGPL
README
README.EXT
README.EXT.ja
README.ja
   
【出力データ】(「if (FileTest.file?(name))」の条件がない場合)
.
..
ChangeLog
COPYING
COPYING.ja
doc
ext
GPL
instRuby.rb
LEGAL
LGPL
MANIFEST
misc
mkconfig.rb
README
README.EXT
README.EXT.ja
README.ja
Rubytest.rb
sample
ToDo
   



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

サブフォルダの配下にあるファイルも含めたファイル名を出力しますので、「再帰処理」を行います。下記の例では、"c:\ruby\doc\ruby\ruby-1.9.1\"のフォルダにあるファイルをサブフォルダも含めて、出力しています。実際に応用する場合は、入出力データのファイル名等変更して利用します。

【スクリプト】
# readdir2.rb   
# 内容 : フォルダ内のファイル名出力    
# Copyright (c) 2002-2015 Mitsuo Minagawa, All rights reserved. 
# (minagawa@fb3.so-net.ne.jp)   
# 使用方法 : c:\>ruby readdir2.rb   
#   

# ファイル名を出力するフォルダ  
dir_name    =   "c:/ruby/doc/ruby/ruby-1.9.1/"  
# 中間ファイルのオープン    
out1_file   =   open("temp.txt","w")    

# フォルダ内の処理(再帰処理)    
def s_file_name(dir_name,out1_file) 
    file_name   =   Dir.open(dir_name)  
    file_name.each  { |name|    
# 通常のファイルの場合  
        if      (FileTest.file?(dir_name + name))   
                out1    =   [name,dir_name].join("\t")  
                out1_file.print out1,"\n"   
# フォルダの場合(カレントフォルダと親フォルダを除く)    
        elsif       ((name  !=  ".")    &&  
                (name   !=  ".."))  
                sv_dir_name =   dir_name    
                dir_name    =   dir_name + name + "/"   
# サブフォルダ内の処理(再帰処理)    
                s_file_name(dir_name,out1_file) 
# カレントフォルダに戻る    
                dir_name    =   sv_dir_name 
        end 
    }   
end 

# 主処理    
s_file_name(dir_name,out1_file) 

# ファイルのクローズ    
out1_file.close 

#   
# 中間ファイルを全部読み込む。  
in1_file    =   IO.readlines("temp.txt")    
# 出力ファイルのオープン    
out1_file   =   open("filename.txt","w")    

# ソートキーの入っている項目番号    
sortitem    =   [1,0]   
# ソートキーをセットするハッシュのキー  
hash_key    =   nil 
# ソートするレコードをセットするハッシュ    
sort_rec    =   Hash.new    
# ソートキーとなる項目番号からソートキーとなる文字列を作っておく。  
#recno番目のレコードがrecordである。    
in1_file.each_with_index    {|record,recno| 
    record.chomp!   
# 入力ファイルをタブで分解する。    
    in1 =   record.split("\t",-1)   
#ソートキーとなる項目の内容をタブで連結してハッシュのキーとする。   
    hash_key    =   " " 
    sortitem.each   {|i|    
        hash_key    +=  in1[i].downcase + "\t"  
    }   
# 同じ値を持つキーが複数存在する場合に以下のように指定する。    
    hash_key    +=  sprintf("%08d",recno)   
# レコードをハッシュの値としてセットする。  
    sort_rec[hash_key]  =   record  
}       
# ハッシュのキーをソートし、キー順にレコードを出力する。    
sort_rec.sort_by{|key| key }.each{|key,value|   
    temp    =   value.split("\t")   
#    out1    =   temp[1] + temp[0]   
#    out1_file.print out1,"\n"   
   out1_file.print value,"\n"  
}   

# ファイルのクローズ    
out1_file.close 
    
【スクリプトとデータのサンプル】

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

【スクリプトの解説】

フォルダの指定

dir_name    =   "c:/ruby/doc/ruby/ruby-1.9.1/"  
out1_file   =   open("temp.txt","w")    

s_file_name(dir_name,out1_file) 

out1_file.close     
   

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

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

def s_file_name(dir_name,out1_file) 
    file_name   =   Dir.open(dir_name)  
   

サブプログラムの内部では、引数の「dir_name」を使用してファイル名を一度に呼び出し、file_nameにセットします。file_nameは一次元の配列として、ファイル名がそれぞれの要素にセットされます。

ファイル名出力

    file_name.each  { |name|    
# 通常のファイルの場合  
        if      (FileTest.file?(dir_name + name))   
                out1    =   [name,dir_name].join("\t")  
                out1_file.print out1,"\n"   
# フォルダの場合(カレントフォルダと親フォルダを除く)    
        elsif       ((name  !=  ".")    &&  
                (name   !=  ".."))  
                sv_dir_name =   dir_name    
                dir_name    =   dir_name + name + "/"   
# サブフォルダ内の処理(再帰処理)    
                s_file_name(dir_name,out1_file) 
# カレントフォルダに戻る    
                dir_name    =   sv_dir_name 
        end 
    }   
   

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

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

ファイル名の並べ替え

# 中間ファイルを全部読み込む。  
in1_file    =   IO.readlines("temp.txt")    
# 出力ファイルのオープン    
out1_file   =   open("filename.txt","w")    

# ソートキーの入っている項目番号    
sortitem    =   [1,0]   
# ソートキーをセットするハッシュのキー  
hash_key    =   nil 
# ソートするレコードをセットするハッシュ    
sort_rec    =   Hash.new    
# ソートキーとなる項目番号からソートキーとなる文字列を作っておく。  
#recno番目のレコードがrecordである。    
in1_file.each_with_index    {|record,recno| 
    record.chomp!   
# 入力ファイルをタブで分解する。    
    in1 =   record.split("\t",-1)   
#ソートキーとなる項目の内容をタブで連結してハッシュのキーとする。   
    hash_key    =   " " 
    sortitem.each   {|i|    
        hash_key    +=  in1[i].downcase + "\t"  
    }   
# 同じ値を持つキーが複数存在する場合に以下のように指定する。    
    hash_key    +=  sprintf("%08d",recno)   
# レコードをハッシュの値としてセットする。  
    sort_rec[hash_key]  =   record  
}       
# ハッシュのキーをソートし、キー順にレコードを出力する。    
sort_rec.sort_by{|key| key }.each{|key,value|   
    temp    =   value.split("\t")   
#    out1    =   temp[1] + temp[0]   
#    out1_file.print out1,"\n"   
   out1_file.print value,"\n"  
}   
   

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

# ハッシュのキーをソートし、キー順にレコードを出力する。
sort_rec.sort_by{|key| key }.each{|key,value|   
    temp    =   value.split("\t")   
    out1    =   temp[1] + temp[0]
    out1_file.print out1,"\n"   
}
   
【出力データ】
ChangeLog   c:/ruby/doc/ruby/ruby-1.9.1/
COPYING c:/ruby/doc/ruby/ruby-1.9.1/
COPYING.ja  c:/ruby/doc/ruby/ruby-1.9.1/
GPL c:/ruby/doc/ruby/ruby-1.9.1/
LEGAL   c:/ruby/doc/ruby/ruby-1.9.1/
LGPL    c:/ruby/doc/ruby/ruby-1.9.1/
README  c:/ruby/doc/ruby/ruby-1.9.1/
README.EXT  c:/ruby/doc/ruby/ruby-1.9.1/
README.EXT.ja   c:/ruby/doc/ruby/ruby-1.9.1/
README.ja	c:/ruby/doc/ruby/ruby-1.9.1/
ChangeLog-1.8.0 c:/ruby/doc/ruby/ruby-1.9.1/doc/
ChangeLog-YARV  c:/ruby/doc/ruby/ruby-1.9.1/doc/
forwardable.rd  c:/ruby/doc/ruby/ruby-1.9.1/doc/
forwardable.rd.ja   c:/ruby/doc/ruby/ruby-1.9.1/doc/
NEWS-1.8.7  c:/ruby/doc/ruby/ruby-1.9.1/doc/
README  c:/ruby/doc/ruby/ruby-1.9.1/doc/
shell.rd    c:/ruby/doc/ruby/ruby-1.9.1/doc/
shell.rd.ja c:/ruby/doc/ruby/ruby-1.9.1/doc/
README  c:/ruby/doc/ruby/ruby-1.9.1/doc/bigdecimal/
・・・・・<以下略>
    
【出力データ(ドライブ名とフォルダ名つきのファイル名にしたとき)】
c:/ruby/doc/ruby/ruby-1.9.1/ChangeLog
c:/ruby/doc/ruby/ruby-1.9.1/COPYING
c:/ruby/doc/ruby/ruby-1.9.1/COPYING.ja
c:/ruby/doc/ruby/ruby-1.9.1/GPL
c:/ruby/doc/ruby/ruby-1.9.1/LEGAL
c:/ruby/doc/ruby/ruby-1.9.1/LGPL
c:/ruby/doc/ruby/ruby-1.9.1/README
c:/ruby/doc/ruby/ruby-1.9.1/README.EXT
c:/ruby/doc/ruby/ruby-1.9.1/README.EXT.ja
c:/ruby/doc/ruby/ruby-1.9.1/README.ja
c:/ruby/doc/ruby/ruby-1.9.1/doc/ChangeLog-1.8.0
c:/ruby/doc/ruby/ruby-1.9.1/doc/ChangeLog-YARV
c:/ruby/doc/ruby/ruby-1.9.1/doc/forwardable.rd
c:/ruby/doc/ruby/ruby-1.9.1/doc/forwardable.rd.ja
c:/ruby/doc/ruby/ruby-1.9.1/doc/NEWS-1.8.7
c:/ruby/doc/ruby/ruby-1.9.1/doc/README
c:/ruby/doc/ruby/ruby-1.9.1/doc/shell.rd
c:/ruby/doc/ruby/ruby-1.9.1/doc/shell.rd.ja
c:/ruby/doc/ruby/ruby-1.9.1/doc/bigdecimal/README
・・・・・<以下略>
    



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