Code.015 2003年01月27日発行
■━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━■
【 Webプログラミング 】
〜 猫的プログラマーとその軌跡 〜
■━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━■
▼毎週月曜日に配信しています。
▼等幅フォントでご覧いただくとキレイに見えます。
▼登録・解除はこちらから可能です。
< http://www.ichikoro.com/webp/ >
※ぜひお友達にもご紹介ください(^^)/
こんにちは、編集長の勝部です。
先日の日経新聞の春秋(第一面の下)に編集後記で以前ご紹介した
「ブラックジャックによろしく」が取り上げられていました。
いやー、そんなに売れていたとはビックリです(笑)
でもこれは大人が読むマンガなんですよね。これほど考えさせられ
る読み物って、なかなかお目にかかりません。まだの方はぜひ一度
手にとってみてください。
※お詫び
前回のメルマガ(Code.14)で激しい誤植がありました。
Subject欄と本文あわせ「MDB」となっている箇所は「DBM」
の誤りです。ご迷惑をおかけしまして申し訳ございません。
また、最新の誤植情報につきましてはBBSの方に随時アップ
しています。こちらもあわせてご覧いただければと思います。
http://www.ichikoro.com/webp/bbs/sylpheed.cgi?c=r&n=17
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
CGI(Perl)ファイル処理 その8:「DBMを使おう! 中編」
──────────────────────────────────────
今回はDBMを『使う』方のCGIをご紹介します。
※詳しい実行方法と解説はソースの下の方(メルマガの
真ん中あたり)にあります。
Mission : 郵便番号から住所を調べるCGIを作れ
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
○問題
7桁の郵便番号を入力すると、その住所を表示する
CGIを作成せよ。今回はDBMを使用すること。
今回のサンプルを試すには、前回作成した郵便番号の
データが必要です。
・前回のメルマガ
http://www.ichikoro.com/webp/bk/00059/
※ダウンロード後、データ変換CGIを
実行してください。
データを用意したら、今度はDBMファイルの作成を行
います。下記のCGIを動作させてください。
───────────
ソース1(DBM作成)
───────────
#!/usr/bin/perl
;#
;# DBMを作成する
;#
use SDBM_File;
use CGI::Carp qw(fatalsToBrowser); #エラー時にブラウザへ表示
use Fcntl;
#-------------------------------------------------#
# ▼ココを設定する▼ #
#-------------------------------------------------#
#■変換後のファイル
$file = "KEN_ALL_CONV.CSV";
#■作成するDBMの名前
$dbm_name = "SDBM_postcd";
#-------------------------------------------------#
# ▲ココまで▲ #
#-------------------------------------------------#
#--------------------------#
# 作成開始 #
#--------------------------#
tie(%h, 'SDBM_File', $dbm_name, O_RDWR|O_CREAT, 0600);
#-- データを突っ込む --#
open(DAT, $file) or die("Can not open file:$file ($!)");
while(<DAT>){
chomp;
my ( $code, @addr ) = split(/,/);
$h{$code} = join("", @addr);
}
close(DAT);
untie %h ;
#--------------------------#
# 処理終了のメッセージ #
#--------------------------#
print "Content-type: text/html\n\n";
print "<H2>OK</H2>\n";
print "DBMを作成しました\n";
exit(0);
__END__
以下の二つのファイルが出来たことを確認してください。
・SDBM_postcd.pag
・SDBM_postcd.dir
※$dbm_nameの名前を変更した場合、
*.pag, *.dir の二つのファイルができます。
これで準備は完了です。
次はいよいよ検索を行ってみましょう!
────────────
ソース2(郵便番号検索)
────────────
#!/usr/bin/perl
;#
;#郵便番号検索CGI
;#
#----------------------------------------------------------------------#
# モジュール #
#----------------------------------------------------------------------#
use strict; #コーディングを厳格化
use CGI qw(:cgi); #フォームデータ取得
use CGI::Carp qw(fatalsToBrowser); #エラー時にブラウザへ表示
use Fcntl;
use SDBM_File;
#-------------------------------------------------#
# ▼ココを設定▼ #
#-------------------------------------------------#
#■DBMファイル
use constant DBM_NAME => "SDBM_postcd";
#-------------------------------------------------#
# ▲ココまで▲ #
#-------------------------------------------------#
#======================================================================#
# メインルーチン #
#======================================================================#
package main;
{
my $search_flag = 0; #検索処理を行ったか?
my $hit_flag = 0; #検索した結果見つかったか?
my $addr = ''; #表示用の住所を格納する
my $q = new CGI();
#-----------------------------------#
# 引数取得 #
#-----------------------------------#
my $post_cd = $q->param("post_cd"); #郵便番号
#-----------------------------------#
# ヘッダ表示 #
#-----------------------------------#
$| = 1;
print $q->header( -type => "text/html",
-charset => "Shift_JIS" );
print_header();
#-----------------------------------#
# 検 索 #
#-----------------------------------#
if( $post_cd =~ /^([0-9]{7})$/ ){ #入力が正しければ検索
my %h;
tie(%h, 'SDBM_File', DBM_NAME, O_RDONLY, 0600);
#----------------------------#
# 検索開始 #
#----------------------------#
$search_flag = 1; #検索フラグを立てる
if( exists($h{$post_cd}) ){ #入力された郵便番号が存在するか
$hit_flag = 1; #あればヒットフラグを立てる
#-- 表示用の住所を作成 --#
$addr = $h{$post_cd};
}
untie(%h);
}
#-----------------------------------#
# 結果表示 #
#-----------------------------------#
if( $hit_flag ){
#-- ヒット --#
print "<H3>〒$post_cd $addr</H3>\n";
}
elsif( $search_flag ){
#-- ハズレ --#
print "<H3>No Hit</H3>\n";
}
else{
#-- 検索しなかった(入力ミス、初期起動時) --#
;
}
#-----------------------------------#
# フッタ表示 #
#-----------------------------------#
print_footer();
#-----------------------------------#
# 正常終了 #
#-----------------------------------#
exit(0);
}
#--------------------------------------------------------------#
#■ヘッダ表示
# 内容:ヘッダ部分のHTMLを表示する
# 引数:なし
# 戻り値:なし
#--------------------------------------------------------------#
sub print_header{
print <<"END_OF_HTML";
<HTML>
<HEAD>
<META http-equiv="Content-type" content="text/html; charset=Shift_JIS">
<TITLE>郵便番号検索</TITLE>
<STYLE type="text/css"><!--
FORM {
margin: 0px;
}
-->
</STYLE>
</HEAD>
<BODY bgcolor="#FFFFFF">
<FORM>
郵便番号:<INPUT type="text" name="post_cd" size="10"><INPUT type="submit" value="検索"><BR>
<SMALL>※半角数字7桁。ハイフン('-')を入力しない。</SMALL>
</FORM>
<BR>
END_OF_HTML
}
#--------------------------------------------------------------#
#■フッタ表示
# 内容:フッタ部分のHTMLを表示する
# 引数:なし
# 戻り値:なし
#--------------------------------------------------------------#
sub print_footer{
print <<"END_OF_HTML";
<BR>
<HR>
<DIV align="right">All Right Reserved, CopyRight (C) 2003
<A href="http://www.ichikoro.com/webp/" target="_blank">Webプログラミング</A>
</DIV>
</BODY>
</HTML>
END_OF_HTML
}
__END__
───────
実行方法
───────
(1)前回のデータを用意します。
・前回のメルマガ
http://www.ichikoro.com/webp/bk/00059/
※ダウンロード後、データ変換CGIを
実行してください。
(2)テキストエディタ(メモ帳やSimpleText)などでDBM作成CGIを
保存してください。適当な名前(xxxx.cgi)でOKです。
そのまま実行します。
(3)以下の二つのファイルが出来たことを確認します。
・SDBM_postcd.pag
・SDBM_postcd.dir
(4)検索プログラムの方を、テキストエディタなどで保存します。
これもファイル名は適当でかまいません。同じようにデータ
ファイルの指定だけします。
(5)郵便番号を検索してみます。
全国版などを使用し、データ量を多くして検索すると
テキスト版に比べ高速になっているのが一目瞭然だと
思います。
CGIの詳しい実行方法については Code.001 をご参照ください。
http://www.ichikoro.com/webp/bk/00046/
───────
解 説
───────
○DBMって何?
もともとUNIXなどについていた簡易的なデータベースのことです。
DBMは今回紹介するPerlは元よりC言語などからも使用することが
できます。
また一口にDBMといっても下記のようにいくつかの種類があります。
・ODBM
・SDBM
・GDBM
・NDBM
・Berkley DB
それぞれに特徴があり、例えばSDBMは1レコードあたり1k byteしか扱う
ことができません。それに比べNDBNは4k byteまで、Berkley DBにいたっ
ては制限がありません。他にも検索速度やDBMのファイルサイズなどが
異なります。
詳しくはコマンドライン(DOS窓やシェルなど)から下記を
参照してください。
perldoc -m AnyDBM_File
Googleで検索すると日本語訳のページも出てきます。
http://www.google.co.jp/search?hl=ja&q=Perl+AnyDBMFile
○どのDBMを使かうか
まずはサーバ上にどのDBMがインストールされているか調べてみましょう。
管理者に質問するか、下記のプログラムを実行することで使用できるDBMの
種類がほぼわかります。
※AnyDBM_Fileモジュールが同じ事を
内部で行っています。
#----------------------------------#
# 調べたいDBを配列に #
#----------------------------------#
@DB = ( "NDBM_File" # NDBM
, "DB_File" # Berkeley DB
, "GDBM_File" # GNU DBM
, "SDBM_File" # SDBM **Perl標準(大抵入っている)
, "ODBM_File"); # ODBM
#----------------------------------#
# 調べる #
#----------------------------------#
foreach $mod ( @DB ){
#-- 無事にrequire出来れば“使える” --#
if( eval "require $mod" ){
print $mod,"\n";
}
}
今回ご紹介したサンプルでは、Perlのバージョンが5以降であれば
標準で組み込まれているSDBMを使用することにしました。
○どうやって使うの?
基本的な流れは、テキストファイルとほぼ同じです。
(0)前準備(use)
(1)DBMを開く
(2)操作
(3)DBMを閉じる
簡単なサンプルプログラムを用意しました。
まずはこれを順番に見ていきましょう。
;#
;#DBMテスト
;#
use SDBM_File; #SDBMを使用する場合はコレを呼び出す
use Fcntl; #開く際のモード("O_RDONLY"など)を指定する際に使用
#-- DBMを開く --#
tie(%hash, 'SDBM_File', 'DBM_Name', O_RDWR | O_CREAT, 0600);
#-- DBMに一行追加 --#
$hash{'apple'} = 'あっぷる';
#-- データ変更 --#
$hash{'apple'} = 'リンゴ';
#-- DBMにキーが存在するかチェック --#
if( exists($hash{'apple'}) ){
print "Apple is $hash{'apple'} \n";
}
else{
print "Apple is NG\n";
}
#-- DBMからデータ削除 --#
delete($hash{'apple'});
#-- DBMを閉じる --#
untie(%hash);
まずは前準備といきましょう。
> use SDBM_File; #SDBMを使用する場合はコレを呼び出す
> use Fcntl; #開く際のモード("O_RDONLY"など)を指定する際に使用
どのDBMを使用するかで、最初の一行は変わってきます。
ここではSDBMを使用するため下記のようにしました。
> use SDBM_File; #SDBMを使用する場合はコレを呼び出す
これがBerkeley DBであれば、
> use DB_File;
とします。
Fcntlについては後述します。
※後のDBMは、use [DBM名]_File; とすることで
使用できます。
○DBMを開く
「開く」という言い方は tieを使用する場合あまり正しくないの
ですが、イメージ的にはそんな感じです。
> #-- DBMを開く --#
> tie(%hash, 'SDBM_File', 'DBM_Name', O_RDONLY, 0600);
それぞれが何を表しているかと言うと、
tie( ハッシュ名 # %hash
, DBMの種類(useした際と同じ物) # SDBM_File
, DBMのファイル名 # DBM_Name
, DBMを開くモード # O_RDONLY(読み込み専用)
, パーミション); # 0600
・ハッシュ名
詳しくは後述しますが、DBMはハッシュを操作するだけで、
データの挿入や削除、書き換えが行えます。その際に使用
するハッシュを指定します。
・DBMの種類
useする際のものと同じ文字列を指定すればOKです。
SDBMであれば 'SDBM_File' とします。
・DBMのファイル名
実際のファイル名を指定します。
・DBMを開くモード
ここでは以下のいずれかを指定します。
(1)読み込み専用 O_RDONLY
(2)読み書き両用 O_RDWR
(3)新規作成 O_CREAT
(4)読み書き両用、存在しなければ新規作成 O_RDWR | O_CREAT
Fcntlモジュールが使用できないと、これらの文字列は
使用できません。ご注意を。
・パーミション
DBMが存在せず、新規に作成する場合に設定される
パーミション(実行権限)をここで指定します。
0644などを指定しましょう。
○操作
操作方法は非常に簡単です。
> #-- DBMに一行追加 --#
> $hash{'apple'} = 'あっぷる';
>
> #-- データ変更 --#
> $hash{'apple'} = 'リンゴ';
>
> #-- DBMにキーが存在するかチェック --#
> if( exists($hash{'apple'}) ){
> print "Apple is $hash{'apple'} \n";
> }
> else{
> print "Apple is NG\n";
> }
>
> #-- DBMからデータ削除 --#
> delete($hash{'apple'});
上記のようにハッシュ(連想配列)を操作するだけです。
特筆すべきは、ハッシュを操作した時点でDBM上にも
それが反映されている点です。
つまり、
> #-- DBMからデータ削除 --#
> delete($hash{'apple'});
という一行を実行した瞬間、ハッシュ上から無くなる
とともに、DBM上からも消えてしまうのです。
○DBMを閉じる
これはもうそのままですね。
やはり untie を使用する場合、「閉じる」というのは
適切な表現ではないのですが(^^;
> #-- DBMを閉じる --#
> untie(%hash);
○どれぐらい速くなっているの?(簡単ベンチマーク)
簡単なベンチマークを取ってみたいと思います。
ベンチマークのとり方について詳しく書くと、それだけで本が
一冊かけてしまいますので、ここではかなり簡易的なやり方です。
ローカル環境でWebサーバを動作させ、以下のソフト
を使用して計測してみたいと思います。
・Webベンチ(Windows系)
http://www.vector.co.jp/soft/win95/net/se179441.html
いくつかのテストデータを抽出します。
今回はランダムに取り出した以下の郵便番号を使用します。
0620042 北海道,札幌市豊平区,福住二条
3293437 栃木県,那須郡那須町,蓑沢
5013754 岐阜県,美濃市,さくらが丘
4211404 静岡県,静岡市,栃沢
8996502 鹿児島県,姶良郡牧園町,三体堂(その他)
テキストファイルの場合、南下するほどファイルの下の方にデータが
あります。そのため検索時間が長くなることになります。それを踏ま
えてみてみましょう。
・テキストファイル
郵便番号 受信スピード(byte/second)
-------------------------------------
0620042 1,044
3293437 589
5013754 436
4211404 404
8996502 273
・SDBM
郵便番号 受信スピード(byte/second)
-------------------------------------
0620042 919
3293437 949
5013754 996
4211404 1,018
8996502 1,030
受信スピードは一秒間にどれだけの転送があったかを示すものです。
つまり値が高ければ高いほど速いということになります。
データ量が少ない場合は、DBMを使用してもしなくても変わりません。
むしろ速い場合もあります。しかし大量のデータを処理しなければ
ならない際には、結果は一目瞭然ですね。
○互換性の問題
今回作成したSDBMのデータ(*.pag, *.dir)は、残念ながら他のDBMとは
互換性がありません。変換プログラムなどを通す必要が出てきます。
ここまでのことを考えた場合、少量のデータを扱う場合はテキスト
ファイルをおすすめします。互換性に優れ、異なる環境間を移動す
るのに適しています。またDBMと違い、テキストエディタなどで簡
単に修正・加工できるのも強みです。
何でもかんでもDBMを使えばいいという物ではありません。
それぞれの長所・短所をしっかりと理解して使ってください。
───────
次回予告
───────
SDBMには排他制御の機能がありません。
そこで次回はflockを使用できる Berkeley DBと、
SDBMなどでの排他制御方法をご紹介したいと思います。
───────
配信予定
───────
ファイル処理編の配信一覧です。
・CGI(Perl)ファイル処理 その1:「ファイルを読む」
http://www.ichikoro.com/webp/bk/00053/
・CGI(Perl)ファイル処理 その2:「ファイルへの書き込み」
http://www.ichikoro.com/webp/bk/00054/
・CGI(Perl)ファイル処理 その3:「ファイルロック:flock 前編」
http://www.ichikoro.com/webp/bk/00055/
・CGI(Perl)ファイル処理 その4:「ファイルロック:flock 後編」
http://www.ichikoro.com/webp/bk/00056/
・CGI(Perl)ファイル処理 その5:「ファイルロック:mkdir編」
http://www.ichikoro.com/webp/bk/00057/
・CGI(Perl)ファイル処理 その6:「ディレクトリ操作」
http://www.ichikoro.com/webp/bk/00058/
・CGI(Perl)ファイル処理 その7:「DBMを使おう! 前編」
http://www.ichikoro.com/webp/bk/00059/
・CGI(Perl)ファイル処理 その8:「DBMを使おう! 中編」<<今回
・CGI(Perl)ファイル処理 その9:「DBMを使おう! 後編(ロック)」
取り上げて欲しいテーマやご意見・ご要望はぜひ以下
までおよせください。
・BBS
http://www.ichikoro.com/webp/bbs/
・メール
mm-webp@ichikoro.com
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ここが知りたい! WebプログラミングQ&A
──────────────────────────────────────
※今回はオヤスミです。
イキナリかよ!(三村風)
★募集中!
Webプログラミングではこのコーナーで聞いてみたいご質問を
受け付けております。メルマガで取り上げた内容と違っても
OKです。お気軽にお寄せください。
mm-webp@ichikoro.com
(かつべへダイレクトに届きます)
───────
分からない
───────
いまいちよく分からない場合は、以下で聞いてみることも
できます。
・サポートBBS
このメルマガ専用のサポート掲示板です。
勝部が(分かる範囲内で)ギモンにスパッとお答えします。
メールで聞くより高速です。お気軽にお書き込みください(^^)/
http://www.ichikoro.com/webp/bbs/
・CGIプログラミングML
CGIなどWebに関する話題を繰り広げるメーリングリスト。
このメルマガとは関係ありませんので発言時は注意を。
http://www.ichikoro.com/cgi/ml/
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
編 集 後 記
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
配信が遅れてしました(^^;
というわけでQ&Aも今回はオヤスミです。
派手に誤植はするし。もう、ホントすみませぬ。
またまた週末は広島に行ってきました。
と思って色々書こうと思案していたのですが、考えているうちに
何だか切ない気持ちになってきたのでまたにします(ーー;)
今回の旅行のお供に、売日直後(去年の秋くらい)に買って以来、ほっぽっておいた
ままだった村上春樹さんの「海辺のカフカ」を持っていったのですが、これが今回
の旅行にピッタシ。本には出逢うタイミングっていうのがあるもんなんだなぁと改
めて感じました。
何だか久しぶりにとりとめない編集後記ですな(^^;
すみません、何か情緒不安定です。
といっても体は元気なのでご心配なく。
また来週お会いしましょう! (^-^)/~~~
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
【 Webプログラミング Code Sample 】
発 行 : ichikoro.com
発行責任者 : 勝部 麻季人
< katsube@ichikoro.com >
Webサイト : < http://www.ichikoro.com/webp/ >
お問い合わせ先 : < mm-webp@ichikoro.com >
Powerd by まぐまぐ
All Right Reserved, CopyRight(C) 2001-2003 Webプログラミング Code Sample
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■