2004年3月4日号

━━━━━━━━━━━━━━━━━━━━━ 2004.03.04 Vol.919 ━━━━━
 ■□■□■
 ■□■□■ 日刊「WEBのツボ!」
 □■□■□              http://www.soho-union.com/
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
                             配信部数 3300部

「続 システムはオブジェクト指向 Ruby & Flash」(#004)
                                                        福井修@Fsys.NET

【○】本日のお題 「 Ruby でファイル操作入門 」━━━━━━━━━━━━

こんにちは、Fsys福井システムリサーチの福井です。
あっという間に3月になりました。時間は日々流れていますねえ。

前回「Ruby サーバサイドプログラム再入門」注1)にてサーバサイドでのプログ
ラムで時刻出力(文字列操作)について実例を示しました。いかがでしたか?

またまた言いますが、Webでは、結局プログラミングを避けて通れません。

プログラミングは、表現の方法のひとつです。絵を描いたり、曲を作ったり、歌
ったり、文章を書いたりと同じです。楽器が無いと演奏できないように、紙とペ
ンが無いと書けないように、コンピュータが無いとプログラムできません。

しかし、もうPCは、業務にも日用品としても必須なアイテムになっています。
今 PC無しで仕事になりますか? いつの間にこうなってしまったんでしょうね。
日々日常コンピュータをさわっていてデジタルコンテンツをハンドリングするに
はもうプログラムするしかありません。

創り出す事、生み出す事、表現する事は楽しいことです。表現する手段のひとつ
に『言語』があります。

言語を使う。という意味では、しゃべったり聞いたり読んだり書いたりするのは、
日本語でも外国語でも同じです。そしてプログラムも表現にプログラム言語を使
うだけで読んだり書いたりするのは同じです。その端的な例としてこの記事中に
も、説明文とプログラムのソースコードが、シームレスに混在します。

プログラムするのはコンピュータを操る命令を使うだけのことで、FORTRANでも
BASICでもC/C++/C#でもJavaでもRubyでもActionScriptでも目的は同じです。
HTMLもHiper Text Markup Language=言語ですしXMLSQLUMLも言語です。
結局コミュニケーションするための表現方法です。

小説家だけが文章を書くのではなく必要な人が文章を書くように、プログラマだ
けがプログラムするのでなく、必要な人は必要に迫られてプログラムすれば良い
のです。WebデザイナもFlashするならActionScriptが書けないとやっていけない
でしょう。

苦役としてプログラムするか、楽しみとしてプログラムするか道は2つあります。

ソースなんか見たくもない言語もありますし、人が書いたソースを是非見てみた
いと思う言語もあります。

プログラム言語との出会いも 『 縁 』でしょう。

何かやりたいことがあって、その手段としてプログラムする訳です。

Webでプログラミングを避けて通れないのであれば、苦役としてのプログラムで
なく、楽しみとしてプログラムしたいものです。言語の選択は、大事です。

さて、オブジェクト指向の話題も少し
■ オブジェクト指向の世界(1) 流れ去るものと不変なもの
http://www.atmarkit.co.jp/farc/rensai/column/world01/world01.html
は、良い記事でおすすめです。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
■ Rubyでファイル操作
────────────────────────────────────
今回は、ファイル操作に進んでみましょう。いろいろな要素が登場しますので、
だんだん習熟して行くわけです:-)

少し先週の予告とはずれますが、WebServerは置いておいて単体で動作させます。

1.【 ちょっと準備 】─────────────────────────
Rubyのプログラム行で # はそれ以後は、コメントとして扱われます。
シェルスクリプトPerl でも同様ですね。

では、CGIプログラムの先頭行の
#!/usr/bin/perl
や
#!/usr/local/bin/ruby
や
#!c:\program files\ruby\bin\ruby
なども単なるコメントでしょうか?

これは単なるコメントではありません。この先頭行での #! は、お約束として特
別の意味を持っていてそのスクリプト(自分自身)を動作させるインタープリタ
(言語処理プログラム)の場所を指定します。また引数も与えます。
例えば
#!c:\program files\ruby\bin\eruby -Ks -C Shift_JIS

は、eruby の場所と 引数 -Ks -C Shift_JIS を渡すように指定しています。


2.【 文字列出力 】──────────────────────────
まず基本のおさらいから Hello.rb ソースファイルを作成します。

 ---- ここから Hello.rb ------
## Hello.rb
# 文字列出力スクリプト
print 'Hello Ruby!'
 ---- ここまで Hello.rb ------

コマンドラインで実行します。
> ruby Hello.rb
"Hello Ruby!"
と出力されます。簡単ですね。

print は、標準出力するコマンドです。
puts  も、出力するコマンドですが、改行コードを付けてくれます。

print と puts は、改行コードを付けないか付けるかで使い分けます。

3.【 ファイル名指定読み込み 】  ───────────────────
次に テキストファイルを読み込んで出力します。

はじめにc言語などでもファイル操作の基本の open を使います。

外部テキストは、テキストファイルであれば適当に何でも良いのですが
contents.txt を作成します。
 ---- ここから contents.txt ------
こんにちは Ruby
 ---- ここまで contents.txt ------

file1.rb ソースファイルを作成します。
 ---- ここから file1.rb ------
## file1.rb
# ファイル名固定読み込みスクリプト
f = open('contents.txt') # ファイルを指定し開く
while line = f.gets      # 1行読み込み
  print line             # そのまま表示
end
x.close                  # ファイルを閉じる
 ---- ここまで file1.rb ------

コマンドラインで
> ruby file1.rb
と入力すると

こんにちは Ruby

と出力されます。

ファイルをオープンしてファイルのハンドルとかポイントとかを得る訳ですが
Rubyでは、すべてがオブジェクトなので、それはファイルオブジェクトになり
ます。「Rubyでは、値とはオブジェクトのことである」

   オブジェクト.メソッド

という形が、オブジェクト指向プログラミングの基本ですね。

getsというのは、一行読み込んで読み込みに成功した時には、その文字列を返
すメソッドです。

  f.gets

 という表記は、ファイルオブジェクトに対しgetsメソッドを呼び出す事になり
ます。


4.【 ファイル名引数渡し読み込み 】─────────────────
次にファイル名を決め打ちでなく、外部から与える方式でやって見ます。

 ---- ここから file2.rb ------
## file2.rb
# ファイル名引数渡し読み込みスクリプト
file_name = ARGV.shift  # ファイル名を取得
f = open(file_name)     # ファイルを開く
while line = f.gets     # 1行読み込み
  print line            # そのまま表示
end
f.close                 # ファイルを閉じる
 ---- ここまで file2.rb ------

コマンドラインで
> ruby file2.rb contents.txt
と入力すると

こんにちは Ruby

と出力されます。このコマンドラインからの呼び出し&出力確認方法は、プログ
ラム名はその都度異なりますが、同様なので以下省略します。

ちょっと解説します。
 ARGV は、組み込み定数で、プログラム起動時 プログラム名の後ろにつける入
力の並びを受け渡ししてくれる定数(オブジェクト)です。注2)
入力の並びのことを引数(複数あり)といいます。

shift は、先頭の要素を取り除いてそれを返すメソッドです。

5.【 ファイル名引数渡し読み込みイテレータ版 】───────────
 ---- ここから file3.rb ------
## file3.rb
# ファイル名引数渡し読み込みイテレータスクリプト
file_name = ARGV.shift
open(file_name) do |f|
  while line = f.gets
    print line
  end
end
 ---- ここまで file3.rb ------

ファイルオブジェクトに対し、do 〜 end のブロックで繰り返します。
ファイルのクローズは、自動で行われます。

6.【 ファイル名引数渡し読み込みFileクラス版 】───────────
 ---- ここから file4.rb ------
## file4.rb
# ファイル名引数渡し読み込みFileクラス版スクリプト
file_name = ARGV.shift
File.foreach(file_name) do |line|
  print line
end
 ---- ここまで file4.rb ------

ファイル操作については、Fileクラスが準備されていますので、
Fileクラスのメソッドを使うというやり方もあります。注3)
Rubyのファイル操作では、この方法が正道でしょう。

foreachメソッドは、path で指定されたファイルの各行に対して繰り返すメソ
ッドです。注4)


7.【 ファイル名複数対応読み込みFileクラス版 】───────────
 ---- ここから file5.rb ------
## file5.rb
# ファイル名複数対応読み込みFileクラス版スクリプト
while file_name = ARGV.shift
  File.foreach(file_name) do |line|
    print line
  end
end
 ---- ここまで file5.rb ------

実は、file4までは、わかりやすくする為に引数に複数のファイル名が指定され
ても対応していませんでしたが、file5 では複数に対応です。
違いに注目してみて下さい。

8.【 ファイル名複数対応読み込みARGF版 】──────────────
 ---- ここから file6.rb ------
## file6.rb
# ファイル名複数対応読み込みARGF版スクリプト
while line = ARGF.gets
  print line
end
 ---- ここまで file6.rb ------

新しい 組み込み定数 ARGF 登場です。注5)
ARGF はスクリプトに指定した引数 (ARGV を参照) をファイル名とみなして、そ
れらのファイルを連結した 1 つの仮想ファイルを表すオブジェクトです。

このファイルオブジェクトに対してgetsメソッドを使用することで、随分すっき
りしますが、組み込み定数 ARGF に慣れるまではちとわかりにくいところです。

9.【 ファイル名複数対応読み込みARGF.each版 】───────────
 ---- ここから file7.rb ------
## file7.rb
# ファイル名複数対応読み込みARGF.each版スクリプト
ARGF.each do |line|
  print line
end
 ---- ここまで file7.rb ------

さらにeachメソッドイテレータを使うとより美しいパターンになります。注6)

10.【 ファイル名複数対応読み込みwhile line gets版 】───────
 ---- ここから file8.rb ------
## file8.rb
# ファイル名複数対応読み込みwhile gets版スクリプト
while line = gets
  print line
end
 ---- ここまで file8.rb ------

プログラムは簡潔ですが、暗黙のルールに従っているので、はじめは敷居があり
ます。慣れてくると簡潔な表現ではあります。

関数形式の呼び出しgetsのレシーバ(メソッドの受け手)は、main。
mainは、getsというメッセージを受け取ると、それをARGFに転送する動作をしま
す。故に ARGF.getsと書くところを getsと書くことができます。

11.【 ファイル名複数対応読み込みwhile gets版 】──────────
 ---- ここから file9.rb ------
## file9.rb
# ファイル名複数対応読み込みwhile gets版スクリプト
while gets
  print 
end
 ---- ここまで file9.rb ------

getsは コマンドラインに指定されたファイルから1行読み込んで,組み込み変数
$_ に代入しますので、暗黙の変数として $_を使うと print の引数も省略でき
ます。注7)

ここまで暗黙の省略を使うとかえってわかりずらいプログラムになるかもしれま
せん。

しかし ここまで簡潔に書くことができるのです。

12.【 複数DOSファイルの改行コードをUnixの改行コードに直す 】───
実用的な応用として改行コードを変える例です。

 ---- ここから dos2unix.rb ------
## dos2unix.rb
#複数DOSファイルの改行コードをUnixの改行コードに直す
while line = ARGF.gets
  print line.chop, "\n"
end
 ---- ここまで dos2unix.rb ------

.chop は文字列の最後の文字を取り除きます(終端が"\r\n"であれば2文字取り除
きます)。chop は最後の文字を取り除いた文字列を生成して返します。

終端の2文字"\r\n"を、1文字"\n"に変えることになります。

結果をファイルに書き出すには、標準出力をリダイレクトします。

例)> ruby dos2unix.rb hogehoge.dos > hogehoge.unix

まあ本当に実用的には、Shift_JISEUC にコード変換も必要ですので、それ
は次回にまわします。

13.【 指定したuriを読み出す 】───────────────────
最後にWebのツボな応用としてファイル指定のようにuriを指定してサイトを見に
行く例です。

これには open-uri ライブラリを使用します。Ruby1.8では標準添付です。注8)
当然IPリーチャブルな環境でないと動作しません。

 ---- ここから readuri.rb ------
## readuri.rb
#引数のuriを読み出す
require 'open-uri'
uri = ARGV.shift  # 引数のURIを渡す
open(uri) {|f| 
  puts f.read 
}
 ---- ここまで readuri.rb ------

コマンドプロンプトで読み出す uri を渡します。
例として googleで試してみます。
> ruby readuri.rb http://www.google.co.jp/

このたった5行のプログラムで サイトの発信情報を読み込んで標準出力に出力
出来るのです。


━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
■ まとめ
────────────────────────────────────
 今回は Rubyでのファイル操作の入門を解説しました。
 
VB,C++,Java,Perl,PHP..のプログラムを経験した方々は、それらでのファイル操
作と較べて、どう感じられましたでしょうか?

イテレータ(繰り返し、反復)をいかに簡潔に表現できるかで、プログラムの美
しさが評価できると思います。

今回の例では、標準入出力というUnixの考え方への入り口にもなっていますし、
Perlとかぶるところもあります。スクリプトでファイル操作が簡単にできること
を体験して、さらなる課題(XML操作など)への基礎としましょう。


また 次回をお楽しみに。

  
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
※ 注釈、資料、参考情報
────────────────────────────────────
注1) 続 システムはオブジェクト指向 Ruby & Flash (#003)
    「Ruby サーバサイドプログラム再入門」
http://www.melma.com/mag/02/m00020302/a00000705.html

注2) Ruby 組み込み定数
http://www.ruby-lang.org/ja/man/index.cgi?cmd=view;name=%C1%C8%A4%DF%B9%FE%A
4%DF%C4%EA%BF%F4

注3) Fileクラス
http://www.ruby-lang.org/ja/man/index.cgi?cmd=view;name=File;em=File

注4) 繰り返し foreachメソッド
http://www.ruby-lang.org/ja/man/index.cgi?cmd=view;name=IO;em=foreach

注5) 組み込み定数 ARGF
http://www.ruby-lang.org/ja/man/index.cgi?cmd=view;name=ARGF;em=ARGF

注6) イテレータ each
http://www.ruby-lang.org/ja/man/index.cgi?cmd=view;name=%A5%E1%A5%BD%A5%C3%A
5%C9%B8%C6%A4%D3%BD%D0%A4%B7;em=each#a.a5.a4.a5.c6.a5.ec.a1.bc.a5.bf

注7) 組み込み変数 $_
http://www.ruby-lang.org/ja/man/index.cgi?cmd=view;name=%C1%C8%A4%DF%B9%FE%A
4%DF%CA%D1%BF%F4;em=%24_

注8) ライブラリ open-uri
http://www.ruby-lang.org/ja/man/index.cgi?cmd=view;name=open-uri.rb

【プロフィール&近況】
前回にも表明しましたが、事務所を引っ越しました。
JR神戸駅 北東5分 高速神戸駅 北東3分 湊川神社神戸地方裁判所正面
■ 新住所  650-0016 神戸市中央区橘通2−3−12 橘ビル302号
■ TEL/FAX 078-341-5346
■ 場所地図
http://map.yahoo.co.jp/pl?nl=34.40.47.844&el=135.10.55.519&la=1&sc=3&CE.x=14
3&CE.y=301
です。近くにいらっしゃったら、どうぞお寄り下さい。

どなたか良い看板屋さんをご存じでしたら是非紹介してください^^ まだ募集中です。

福井 修 ( FUKUI Osamu )o-fukui@po.iijnet.or.jp
福井システムリサーチ http://fsys.net/  主幹。システム構築歴27年。
システム構築エキスパート
日本Linux協会、神戸商工会議所情報処理学会、関西IT共同体 会員
関西ソーホ・デジタルコンテンツ事業協同組合デジタルハリウッド神戸校 Java講師