言語
サーバ関連
ツール
API
読み物
その他
[AD]
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 発行責任者 : 勝部 麻季人 < mailto:katsube@ichikoro.com > Webサイト : < http://www.ichikoro.com/webp/ > お問い合わせ先 : < mailto:mm-webp@ichikoro.com > Powerd by まぐまぐ All Right Reserved, CopyRight(C) 2001-2003 Webプログラミング Code Sample ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■