2004年3月18日号

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

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

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


こんにちは、Fsys福井システムリサーチの福井です。

前回「Ruby でファイル操作入門」注1)にてファイル読み込みの実例を示しまし
た。最後の応用で URI 注2)を指定すると Webサイトも読み込めてしまうのは、
興味深いところだったでしょう。

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

今回は、ファイル操作の続きで、標準入出力、リダイレクト、文字コード変換、
ファイルの書き込みに話しをすすめます。

ノートPCにWindowsXPという環境で、どんどん楽しいプログラムを進めましょ
う。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
■ 標準出力リダイレクト
────────────────────────────────────
はじめに、前回、標準出力リダイレクトという方法でファイル書き込みが一部登
場していました。これについて復習しておきます。

前回の 改行コードを変えるサンプルで

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

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

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

という例を挙げました。ここは、重要なので以下に解説します。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
■ 標準入力 と 標準出力
────────────────────────────────────
一般論ですが、

  入力を受け付けて、処理をして、出力する。

     入力  ─→ 処理 ─→ 出力

  という形は、基本です。


何か入力をしたら処理プログラムがそれを受け付けて動作して出力する。

では、PCでの入力や出力は、具体的には、何になるのでしょうか。

計算機は、歴史的には、「 端末(=Terminal、ターミナル)」で、キーボード
からキー入力を受け付けて、端末(画面)に出力していました。このスタイルは
今も脈々と続いてはいますが、Windowsでは、グラフィカルユーザインターフェ
ースがメインになり、「端末」に相当する画面は、わざわざ「スタート」→
「プログラム」→「アクセサリ」→「コマンドプロンプト」と呼び出さないと
目に触れないないように埋もれてしまいました。

それはそれとして、この端末からの入力を「標準入力(Standard Input)STDIN」,
端末への出力を「標準出力(Standard Output)STDOUT」と呼んで、プログラムの
入出力は、端末に対して行うのが基本です。

入出力には、いろいろな装置がありますから、「ドライバ」呼ばれるプログラム
を介するとそれらの外部装置とつながることになります。例えばプリンタドライ
バをインストールしたら、そのプログラムの動作を介してプリンタにつながるこ
とになる訳です。

プログラムは、入力を受け付けて、処理をして、結果を出力するのですが、この
入力・出力先は、標準としては、端末なのですが、いろいろな機器を割り当てる
ことができるのです。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
■ リダイレクト と フィルタ
────────────────────────────────────
標準出力に出力される文字列ストリームを、ファイルを指定してそこに流し込む
ようにすれば、出力結果が、ファイルに流し込まれます。すなわち書き込まれま
れるのです。このように出力先を切り替えることをリダイレクトと呼んでいま
す。

Windowsの「ヘルプとサポートセンター」の画面で『リダイレクト』を検索する
と「コマンド リダイレクト演算子を使用する」や「フィルタを使用する」など
の解説がヒットしますので、ご参考に。

「 > 」や「 < 」はコマンドリダイレクト演算子と呼ばれていますね。
そして「 | (たて棒)」は、 あるコマンドからの出力を読み取り、別のコマン
ドの入力に書き込む演算子で、パイプとも呼ばれます。 

ファイル(やストリーム)を入力して 情報の一部を加工してファイル(やスト
リーム)に出力するようなプログラムを『フィルタ』とも呼びます。

このフィルタを自由に操れるようになると、デジタルコンテンツの管理パワー
が増大します。

PerlRuby また WSH などのスクリプトが、この分野では強力です。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
■ コード変換フィルタ
────────────────────────────────────
フィルタの例として先週の予告どおり Ruby でコード変換の例もやってみます。

文字コードはいろいろ奥深い 注3) ので一度は、どっぷり浸かって見るのもあり
でしょう。

LinuxUnixでの EUC のファイルを WindowsShift_JIS に変換してみます。
改行コードも EUCの \n から Shift_JIS の \r\n に変更します。

 ---- ここから euc2sjis.rb ------
## euc2sjis.rb
# EUCからShift_JISへコード変換
require 'nkf'
while line = ARGF.gets
  print NKF.nkf('-Es',line).chomp,"\r\n"
end
 ---- ここまで euc2sjis.rb ------

ポイントは nkf です。nkf は、由緒正しい 漢字変換フィルタです。注4)
正式名は、Network Kanji code conversion Filter で C言語で書かれていま
す。 
C言語で書かれたライブラリを Rubyでは、簡単に利用することができますし、
標準的なものは、標準添付されています。注5)

使い方は、次のように プログラム名と入力ファイル名を並べて、さらに標準
出力を指定したファイルにリダイレクトします。

> ruby euc2sjis.rb euc.txt > sjis.txt
                      ↑        ↑
                 入力ファイル 出力ファイル
                 
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
■ メソッド呼び出しとレシーバ
────────────────────────────────────
 ここで、少しオブジェクト指向の復習です。

 オブジェクト指向では、メソッドを実行することで処理が行われます。
 
 「 オブジェクトのメソッドを実行する 」ことは
               ↓↑
 「 オブジェクトにメッセージを送る」ということと解釈します。

 「 オブジェクトは、メッセージを受け取る 」ので、
 「 オブジェクトは、メソッドをレシーブ(receive)する 」もので
 あり『 レシーバ 』と呼称する表現があるのです。

 メソッドを実行するのは、「 オブジェクトに、引数とともにメッセージを
 送る 」という図式です。

 オブジェクト.メソッド名(引数1,引数2.....)

一般的はメソッドは、インスタンスメソッドで、あるオブジェクト(インスタン
ス)をレシーバとして、メッセージ送る(=メソッドを実行する)のです。

これに対して、オブジェクト(=インスタンス)を特定しないで、汎用的に
メソッドを実行したい場合には、どうすればよいのでしょう。
レシーバとして、オブジェクト(=インスタンス)を指定しにくい場合です。

この問題意識をもって先程のeuc2sjis.rb を見てみましょう。

  NKF.nkf... という表記が存在します。
  
この NKF.nkf という表記は、『クラスメソッド』が使われています。
クラスメソッドというのは、レシーバがインスタンスでなくクラスそのもので
ある形です。

クラスメソッドを呼び出す場合、「.」の代わりに「::」を使うこともできま
す。

  NKF::nkf

この :: という関係子は、C++ では、『 メンバ関数 』の定義で使われていまし
た。こちらの表記が、なじむ場面もあるわけです。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
■ Rubyでファイル操作続き
────────────────────────────────────
では、ファイルの埋め込み指定書き込みに進みます。

1.【 ちょっと復習 】─────────────────────────
 ファイル名を固定した読み込みを前回やりました。

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

2.【 はじめの一歩 】─────────────────────────

次のソースファイル file10.rb を作成し、実行します。

 ---- ここから file10.rb ------
## file10.rb
# ファイル名固定書き込みスクリプト
f = open('out.txt','w')  # ファイルを指定し書き込み用で開く
f.print('Ruby file write!!')
f.close                  # ファイルを閉じる
 ---- ここまで file10.rb ------

> ruby file10.rb

コマンドには何も出力されませんが、別ファイル out.txt が作成されて中味に
は、文字列 'Ruby file write!!' が書き込まれているのを確認して下さい。

3.【 ファイルopenモード 】──────────────────────

 open メソッドの第二引数は、モードを指定します。

 'r'  読み込み専用(モード省略時も)
 'w'  書き込み専用。ファイルが無ければ新たに作成。
 'f+' 読み込み/書き込み用
 'w+' 読み込み/書き込み用 無ければ作成。既に存在したらファイルサイズ0に
 'a'  追加書き込み専用
 'a+' 読み込み/追加書き込み用 無ければ作成。

4.【 追加書き込み 】─────────────────────────

追加書き込みには、モードを指定する必要があります。
次のソースファイル file11.rb を作成し、実行します。

 ---- ここから file11.rb ------
## file11.rb
# ファイル名固定追加書き込みスクリプト
f = open('out.txt','a')  # ファイルを指定し追加書き込み用で開く
f.print("\r\n")          # 改行
f.print('next line')
f.close                  # ファイルを閉じる
 ---- ここまで file11.rb ------

> ruby file11.rb

はじめの一歩で書き込んだファイル out.txt に行が追加書き込みされているの
を確認して下さい。

5.【 現在時刻書き込み 】───────────────────────

前々回に使用した時刻表記編集も利用します。

引数の並びのカッコ ( ) はほとんど省略できます。
次のソースファイル file12.rb を作成し、実行します。

 ---- ここから file12.rb ------
## file12.rb
# ファイル名固定時刻書き込みスクリプト
f = open 'time.txt','a'  # ファイルを指定し追加書き込み用で開く
f.print Time.now.strftime("%Y/%m/%d %H:%M:%S")
f.print "\r\n"           # 改行
f.close                  # ファイルを閉じる
 ---- ここまで file12.rb ------

> ruby file12.rb

何度か起動して、ファイル time.txt に現在時刻が追加書き込みされているのを
確認して下さい。

6.【 現在時刻でファイル名を決める 】─────────────────

ファイル名も現在時刻から編集できます。月、日、時で作成してみます。
改行コードも一緒に出力するのには、puts が便利です。
次のソースファイル file13.rb を作成し、実行します。

 ---- ここから file13.rb ------
## file13.rb
# ファイル名編集&時刻書き込みスクリプト
fname = Time.now.strftime("%m%d%H") + '.log'
f = open(fname,'a') 
f.puts Time.now.strftime("%Y/%m/%d %H:%M:%S")
f.close                  # ファイルを閉じる
 ---- ここまで file13.rb ------

> ruby file13.rb

何度か起動して、例えばファイル名 031703.log (数字部分は、月、日、時)に
現在時刻が追加書き込みされているのを確認して下さい。

これを応用すれば、プログラムの途中で、変数の値をログに残したりも簡単に出
来ます。


━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
■ まとめ
────────────────────────────────────
 今回は Rubyでのファイル操作の続きで文字コード変換、リダイレクト、メソッ
ド呼び出し、ファイル書き込みを解説しました。

『レシーバ』の概念は、重要です。ActionScript で引っかかるところですよ。

少しずついろいろな要素が出てきましたね。一歩一歩進みましょう。

また 次回をお楽しみに。

  
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
※ 注釈、資料、参考情報
────────────────────────────────────
注1) 続 システムはオブジェクト指向 Ruby & Flash (#004)   
    「Ruby でファイル操作入門」
http://www.melma.com/mag/02/m00020302/a00000714.html

注2) URI は Uniform Resource Identifier の略でインターネット上に存在
  する情報資源の場所を指し示す記述方式。
  URL は Uniform Resource Locator の略で、正式名称 URI に対する俗称。
・ URIs, URLs, and URNs: Clarifications and Recommendations 1.0
http://www.w3.org/TR/uri-clarification/URI : URL and URN - Ancient library
http://www.alib.jp/html/uri

注3) 文字コード問題解説
・ 日本語フォント、文字コードリンク集
http://www.zukeran.org/shin/jdoc/

・ ほら貝主宰 加藤弘一さんの 文字コード問題を考える
http://www.horagai.com/www/moji/小形克宏の「文字の海、ビットの舟」 文字コードが私たちに問いかけるもの
http://www.watch.impress.co.jp/internet/www/column/ogata/

・『文字コード』豊田英司
http://dennou-t.ms.u-tokyo.ac.jp/arch/zz1998/mozi/zengaku.html

・『漢字コードとコーディング方法』今田 庸介
http://tron.is.s.u-tokyo.ac.jp/~imada/kcode/kcode.html

注4) nkf のページ
http://www.ie.u-ryukyu.ac.jp/~kono/nkf/

注5) Rubyリファレンスマニュアル - NKF
http://www.ruby-lang.org/ja/man/index.cgi?cmd=view;name=NKF


【プロフィール&近況】
前回にも表明しましたが、事務所を引っ越しました。
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=143&CE.y=301
です。近くにいらっしゃったら、お寄り下さい。

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

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