ファイル - みる会図書館


検索対象: 月刊 C MAGAZINE 2002年2月号
73件見つかりました。

1. 月刊 C MAGAZINE 2002年2月号

0 0 0 座 回操 小薗三典 / 中井信 前回に引き続きファイル操作について説明します。今回はランダムアクセス 処理を取り上げます。 Fig. 1 ファイル内の相対位置イメージ 始めに みなさん , こんにちは。今回も前回に続 いてファイル操作に関する説明を進めてい きますが , 主にランダムアクセス処理につ いて説明していきます。ランダムアクセス 処理とは , ファイル内の読み書きを開始し たい位置を指定して , 任意の位置から読み 書きを行うアクセス方法です。またファイ ル操作と構造体を使用して , ちょっとした プログラムを作成します。 ファイル操作 ( 2 ) ファイル処理では常に , ファイル内のど の位置を処理しているかという情報を , フ rewind(filepointer) ァイル位置指定子 ( ファイルポジションイ ンジケータ ) に持っています。シーケンシ TabIe 2 ファイル指定子 指定子 ャルアクセス処理では , ファイル位置指定 SEEK SET 先頭位置を基点にする 子は参照するだけです。しかし , ランダム アクセス処理では , ファイル位置指定子に SEEK CUR 現在位置を基点にする ポジションを指定することで自由に処理を SEEK END ファイルの終端を基点にする 行う位置を移動させることができます。 ファイル位置指定子を設定した後は , 前 紹介します (Table 1 ) 。 す。 回紹介した関数で読み書きを行います。前 引数。爪 et には + / - どちらの値も指定でき fseek 関数 回紹介したオープン , クローズ , 読み書き ます。 + 値の場合は前から後ろへ移動し , 値の場合は後ろから前へ移動します ( Fig. fseek 関数の書式 ( 使用例 ) は次のように 用の関数は , シーケンシャルアクセス / ラ ンダムアクセス処理で共通に使用できます。 なります。 引数 origin に指定するモードは , 3 種類 fseek( fp, offset, origin 潺 ファイル位置指定子の操作 用意されています (TabIe 2 ) 。これらのモ fseek 関数は , 引数 origin(int 型 ) で指定し た位置から , 引数 offset(long int 型 ) で指定 ードは stdio. h ヘッダファイル中で次のよう に定義されています。 では , ファイル位置に関する標準関数を された変移ぶん , バイト位置を移動させま 68 C MAGAZINE 2002 2 4 3 2 0 ー 2 ー 3 1 ー 4 TabIe 1 ファイル位置に関する標準関数 関数 処理 ファイル内の 0 「 igin を基点に offset fseek( filepointe 「 . で指定したバイト数ぶん移動した位 offset, origin ) 置にファイ丿しイ立置指定子をセットする ファイル内のファイル指定位置を取 得する ファイルの先頭に位置付ける 戻り値 正常終了の場合 0 を返す。工ラーの場 合は 0 以外の値を戻り値として返す バイナリモードの場合 , 先頭を 0 バイ トとする位置を戻り値として返す。 工ラーの場合は long 型の -1 を返す なし。 void 型 ftell( filepointer ) 意味

2. 月刊 C MAGAZINE 2002年2月号

6 ロロ同ロロ Fig. 2 List 1 の実行画面 を、勹マンドプロンプトー List1 0:}CLang!st ・ c>Listl = 顧客管理メニュー 1 . データ人力 2 . レコードの書き換え ( レコード指定 ) 3. データの表示 ( 全データ ) 4 . データの表示 ( レコード指定 ) 処理を選択してください : 点数管理メニュー画面 Fig. 3 Student 構造体 / * 点数管理の構造体 * / struc セ student { int COde ー char name[ 30 s して uc セ Mark { int kokugo ー int sansu; int eigo ー }tensuu; struct Student *Next; / * 次のデータ * / / * 出席番号 * / 展開します。追加 , 更新 , 削除といったす べての入力が完了した時点で , すべてのノ ードをファイルに出力します。 まずグローバル変数として , pStart( 先 頭を指す ) と pEnd ( 最終データを指す ) を用 意します。 main 関数の初期処理としてダ ーノードを作成します。メニュー画面の 各機能は , 以下のとおりです。 全データのクリア 内部関数 CIearList として実装します。現 在メモリ上に入力されているすべてのノー ドを解放します。 pStart の次 ( ダミーノー ド ) からリストをたどって free 関数で領域 を解放します。解放した後は pEnd がダミ ーノードを指すように設定し , さらにダミ ーノードの Next ポインタを NULL クリアし ます (List2)0 ファイルからのテータ読み込み 内部関数 ReadListData として実装しま す。読み込むべきファイル名は引数として 指定されます。ファイルへの書き込み時に は , 出席番号順に書き込まれます。そのた めファイルからの読み込みは , 読み込んだ 順にリストに登録するだけの単純な処理に なります (List 3 ) 。 ファイルへのデータ保存 内部関数 WriteListData として実装しま す。書き込むべきファイル名は引数として 指定されます。リスト上には出席番号順に Fig. 4 ドを " D : ¥ OLang ¥計 c ¥ 0 マガ¥ Samp ¥ Deb ¥ S 日け xe を囓 : 、、、、 テスト点数管理メニュー 1 . 全データのクリア 9. 終了 6 . 現在のデータを表示 5 . データの削除 4 . データの登録・修正 ファイルにデータの保存 2 . ファイルからデータを言売み込む 3 . 4 lSt 全データのクリア 1 : / * リストを初期化する 2 : int ClearList(void) 4 : 5 : 6 : 7 : 8 : 9 : 10 : 11 : 12 : 13 : 14 : 15 : 16 : 17 : ) struct Student *pCurrent, *pNext; / * ダミーノードの次をセット * / = pStart->Next ー whil e ( pCurrent ) { pNext = pcurrent → Next; / * f て ee する前に次を退避 * / free(pCurrent); pCurrent = pNext ー pEnd = pStart; pStart->Next = NULL ー て e し u てれ 0 ー / * ダミーノードの Next をクリア * / ロ X Getlnto C World ! ! / 1

3. 月刊 C MAGAZINE 2002年2月号

6 ロロロロ ファイルの操作のまとめ ( 2 ) Fig. 5 新規ノードの挿入 pSta rt pEnd ファイル位置指定子の操作 ・ランダムアクセス処理ではファイル位置指定子の操作を行う ・ファイル位置に関する関数 ・ fseek 関数・・・ファイル位置をセットする ・ fte Ⅱ関数・・・ファイル内の位置を取得する ・ frewind 関数・・ファイル内の位置を先頭に戻す ・ fseek 関数では 3 種類の指定モードを指定することが可能 ・ SEEK_SET ・・先頭位置を基点にする ・ SEEK_CUR ・・現在位置を基点にする ・ SEEK ー END ・・・ファイルの終端を基点にする < 構造体 > 出席番号 : 3 Next:NULL 造一 構ミ < ダ z < 構造体 > 出席番号 : 1 N ext : く構造体 > 出席番号 : 2 Next: 以上のすべてのソースは付録 CD-ROM に Sample. c として収録しています。他人の 作成したプログラムを読むことは , プログ ラミングの上達にはとても有効です。ラン ダムアクセス処理の例と同様 , ぜひがんば って読破してみてください。 では , Fig. 7 に今回の内容をまとめます。 今回の Homework 今回の Homewo ⅸは今回紹介したプログ ラム例からです。多少今までのものより複 雑かもしれませんが , これまでのまとめと してもぜひチャレンジしてください。 ・ Ex. 10.1 プログラムの実行 今回例題として示した List1 を実際にプ ログラミングして実行してください。 ・ Ex. 10.2 プログラムの完成 今回後半で紹介したリスト構造のプログ ラムを完成させてください。 main 関数を 作成し , List 2 ~ 6 を合成させて , 仕様どお りの動作をするか確認してください。解答 例は付録 CD - ROM の Sample. c を参照してく ださい。 あとがき を理解する努力が技術の向上につながりま に , 構造体 , リスト構造データ , ファイル す。これまでのまとめとして , 気合を入れ 操作を使用したプログラムを紹介しまし た。ソースリストが中心だったため , これ て取り組んでみてください。 今回はファイル操作の後半 , ランダムア 次回の最終回では , C 言語入門レベルと までに比べて少し複雑に感じた方もいるか クセスについて説明しました。さらに , よ して補足しておきたい項目を紹介します。 もしれませんが , 複雑に見えるプログラム り実用的なプログラムの理解を深めるため Getlnto C world ! ! 73 LlSt ノードの削除 1 : int leteNode ( void ) char buf [ 1024 3 : 土 n し de に od 4 : struct Student *pPrior , *pDe 嵭 5 : 6 : p て intf ( 心 n 北削除する出席番号 : ” gets(buf); 8 : delcode = atoi(buf); 9 : 10 : p iO て = pStart; 11 : whiIe(pprior->Next) { 12 : if(pPrior->Next->code = = delcode) { 13 : / * 削除すべきアドレスを退避 * / pDel = pPrior->Next; 14 : pPrior->Next pPrior—>Next->Next; free ( pDeI 16 : / * 削除対象が最終の時 * / if(pDeI = = pEnd) 17 : pEnd = pprior; 18 : 19 : return 0 ー 20 : / * 次のノードへ移動 * / pprior = pPrior->Next ー 21 : 22 : / * 見つからなかった時 * / 23 : pu し s ( 、 n 該当の出席番号は登録されていません、つ 24 : return 1 ー 25 : 26 : ) Fig. 6 ノードの削除 pEnd pStart < 構造体 > 出席番号 : 3 Next:NULL く構造体 > 出席番号 : 2 N ext : く構造体 > 出席番号 : 1 N ext : 体ノ 造一 構ミ くダ z

4. 月刊 C MAGAZINE 2002年2月号

6 ロロロロ の関数を駆使して , ユーザインタフェイス #define 0 SEEK—SET 以上のように , ランダムアクセス機能を を実現しています。ちょっとしたデバッグ #define 1 SEEK—CUR 利用することによりファイル中の任意の位 ツールなどの作成には有効です。ただし , #define 2 SEEK—END テキストモードの場合には , ANSI では以 置より読み書きすることが可能になります 画面からの入力ミスを完全にガードするに 下の 2 通りの場合のみ保証されていますが , はそれなりのステップ数が必要となり , 見 が , どの位置に何が書かれているかという ことはプログラム自身が管理しなければな 処理系が独自の仕様を規定している場合も 通しが悪くなるので , 工ラーチェックを多 少簡略化している部分もあります。 りません。実際の業務プログラムではデー あります。テキストモードで利用する際は 注意が必要です。 タベースシステムを利用したり , あるいは List 1 プログラムの概要 Windows プラットホームでは INI ファイル ・ offset が 0 で , origin には SEEK SET/S EEK END を指定して , ファイルの先 このプログラムは , 30 バイトの名前と 12 やレジストリなどのキーアクセス機能が提 頭もしくは終端に移動する場合 バイトの電話番号をレコード ( 1 つの処理単 供されています。ランダムアクセス機能を ・ origin に SEEK CUR を指定し , 以前の 位 ) としてファイルに書き込みます。書き 利用する機会はあまりないかもしれません fte ⅱ関数の戻り値を指定する場合 が , C 言語の基本動作としては重要なファ 込んだ順番をレコード番号として管理し , 以後このレコード番号により読み込みと更 イル操作の一部です。 貴 ell 関数 新を行います。実行してデータを入力する 再びリスト構造 飛Ⅱ関数の書式 ( 使用例 ) は次のようにな と , カレントディレクトリに samplll. d と いうファイル名でデータが保存されます。 ります。 long Offset = ftell ( fp 潺 メニューに表示されている各機能の概要 本連載も 11 回目を迎え , 残すところ後 1 と , それを実装する関数名を次に示します。 回となりました。そこで今までの総仕上げ 変数 o Ⅱ set には現在のファイル位置がセ ・テータ入力とファイル出力 ( Da ね Outp として , 以前取り上げたリスト構造を使っ ットされます。この値は先頭を 0 としたオ (t) : 名前 ( 30 バイトを超えた部分は無 てちょっとしたプログラムを作成しましょ フセットバイト位置となります。テキスト モードの場合には , fseek 関数でこの位置に 視 ) と電話番号 ( 12 バイトを超えた部分 う。前述したランダムアクセス処理のプロ は無視 ) を 3 人ぶん入力し , シーケンシ グラムと同じような構造を使用し , 生徒の 位置づけるための処理系の定めた値となり ャルに出力する テスト点数管理プログラムを作成します。 ます。 構造体は前々回でおなじみの Student を ・レコードの書き換え (DataChange) : rewind 関数 レコード番号 ( 1 ~ 3 ) を入力し , 該当デ そのまま利用します。第 9 回で紹介した Stu ータを入力されたデータで上書きする dent 構造体を Fig. 3 に示します。 rewind 関数の書式 ( 使用例 ) は次のように ・全データの表示 (DataDispAll) : すべ このプログラム仕様は以下のようなもの なります。 て ( 3 人ぶん ) のデータを表示する とします。 rewind( fp ファイルの先頭から読み直したい場合に ・選択テータの表示 (DataDispSelec) : ( 1 ) 画面より , 出席番号 , 名前 , 点数 ( 国 レコード番号 ( 1 ~ 3 ) を入力し , 該当デ 語 , 算数 , 英語 ) を入力し , リスト構 使用します。 ータを表示する 造に登録する。このとき生徒の点数 ランダムアクセス処理使用例 データは , 出席番号順ではなく任意 関数 DataChange の 115~124 行目 , およ び DataDispSelec 内の 170 ~ 179 行目でラン の順序で入力できるものとする。た では , 実際にランダムアクセス処理を使 ダムアクセス処理を行っています。入力さ だいリスト上には出席番号順に登 用したプログラム例を紹介します (List 1 ) 。 れたレコード番号より先頭からの相対位置 録する。また , 入力された出席番号 を求め , fseek で位置づけた後に読み書き がすでに登録済みであれば , 現在の List 1 を実行すると Fig. 2 に示す画面が 表示されます。 GUI ふ主流となたこの時 を行っています。また DataDispSelec, Dat データと置き換える aDispAII 内ではファイルの Open を「 rb 」モー ( 2 ) 現在入力済みのテータをファイルに 期に , CUI で少々長いプログラムですが ドを指定しているのに対して , DataChang C 言語をマスターした先輩たちも一度は通 保存することができるものとする e 内のファイル Open では「 rb + 」モードを使 ( 3 ) ファイルに保存されたデータを読み った道のはずです。これまで説明してきた ことをある程度使用しているので , 復習の 用している点にも注意してください。ぜひ 込み , さらに追加修正ができるもの 意味も込めてがんばって解読してみましょ 実際にこのプログラムを動かして , 動作と とする ( 4 ) 出席番号を指定して , 1 ノードを削 ファイルの中身を比較して確認してみてく 除することができる List 1 では printf, puts , scanf, gets など ださい。 Getlnto C world ! ! 69

5. 月刊 C MAGAZINE 2002年2月号

nd}Bcc55YincIudeYSDL に移動したとしま す。次にライプラリを Borland 用に変更し ます。まず MinGW32 でインストールする 手順を参考にソースをビルドします。でき あがった SDL.dll から SDL. lib ファイルを作 成します。 > implib -a -c SDL. lib SDL. dll このファイル SDL.1ib はリンク時に必要に なるので c:YBorlandYBcc55Y1ibYSDL などに 移動しておきます。 SDL の配布ファイルである SDL-I. 2.3/src /main にある SDL—main. c をコンパイルして SDL. lib と同じ場所へ置いておきます。以 下のコマンドをプロンプトから , > bcc32 -c -tW -DWIN32 -Ic:*Borland *Bcc55*inc I ude*SDL SDL_main. c と入力して SDL_main. obj を作成し移動しま す。 SDL.d Ⅱは実行に必要なのでパスの通っ たところへ移動します。 ・ SDL プログラムのコンバイル方法 SDL のプログラムや , そのほか配布物は UN Ⅸ環境を前提としているため , そのまま ではメイクコマンドが実行できません。そ こで , 環境構築で行った BCC コンパイル・ リンクオプションに修正を施します。今回 の設定では , コンパイル時に次のオプショ ンを加えます。 -tW -DWIN32 -lc : Bo て land*Bcc55 *inc ー ude*SDL リンク時には次のオプションを加えます。 -aa ー -c -lc : 0 て land*Bcc*l ib*SDL SDL 用の bcc32. cfg と ilink32. cfg をカレン トディレクトリに別途作成しておくとよい でしよう。 リンク時に次のファイルをリンクします。 ・ SDL_main. obj ・ SD 凵 ib ・ imP0臧32 」 ib ・ COW32. ⅱ b ・ cw32. Obj この環境で , SDL を利用するプログラム test. c をコンパイルする場合は , > bcc32 -c test. c > 土は献 32 test. obj *. obj L ヨ遯 24 C MAGAZINE 2002 2 土 mpo てセ 32 . lib COW32. lib cw32. となります。 インストール後の ファイル構成 最終的に次のファイルがインストールさ れます。 obj 1 . SDL のヘッダ・ライブラリ 2. sd ト config スクリプト (Linux, MinGW32) Cygwin, 3. man 用ファイル (Linux, Cygwin) 関数のリファレンスは SDL -1.2.3 / docs に あります。テストプログラム群は SD し 1.2. 3/test にあります。関数は man コマンドで も調べられます。たとえば , $ man SDL—Init と打てば SDL ー lnit 関数の詳細が表示されま す。 SDL を使うための統合環境というもの は存在しません。あと必要なものはエディ タだけです。使いやすいものを用意しまし よう。 サンプルプログラムのコンバイル SDL にはドキュメントのほかにたいへん 有用な情報がサンプルプログラムの中にあ ります。ほとんどの関数の使用例があがっ ているのでぜひ眺めておきましよう。 Linux , Cygwin , MinGW32 を使用する 場合は , SDL のテストプログラムをそのま まコンパイルできます。 SD し 1.2.3 / test / に 入り , $ . /configure;make と打っと , つぎつぎとテストプログラムが ビルドされていきます。たとえばスプライ トのテストプログラムを実行する場合は , Fig. 1 サンプルプログラムの実行例 $ . /testsprite とすれば Fig. 1 のような顔マークが動き回 るウインドウが現れるはずです。 Borland C + + の場合は Makefile を作ってコ ンパイルさせましよう。テストファイル用 に Makefile を用意しました (Makefile. bcc) 。 > make -f Makefile. bcc としたのち , > testsprite とすれば実行します。 Windows で exe ファイルをダブルクリック してファイルを実行したい場合は , SDL.dll のあるディレクトリをサーチパスへ含めて おく必要があります。あるいは exe ファイ ルと同じディレクトリか }windows などに SDL.dII を置きます。 おわりに SDL では , 統合環境などは用意されてお らずコマンドラインとエデイタだけでプロ グラミングを行います。また , ライプラリ はたいへん簡素なものとなっており , ほか のライプラリでは実装されているような機 能であっても自前で処理しなければならな いなど , 未発展な部分もあります。 SDL は パフォーマンスよりもポータビリティ重視 のライプラリです。最大のポイントは Win dows , Macintosh , Linux , FreeBSD 上で コンパイルできる環境を用意するという点 です。また , フリーでゲームプログラミン グ環境を用意してくれるため , ホビープロ グラミングにうってつけといえます。この 大きなアドバンテージを生かして多数のア プリケーションを作って公開し , SDL コミ ュニティを発展させていきましよう。 参考文献 [ 1 ] Simple DirectMedia Layer , http://ww w.libsdl.org/ [ 2 ] Cygwin , http://cygwin.com/ [ 3 ] GCC binary compilers for Wm32 , http: //www.libsdl.org/Xmingw32/ [ 4 ] BorIand C + + CompiIer 5.5 無償ダウンロ ードサービス , http://www.borland.co. jp/cppbuilder/freecompiler/index. html

6. 月刊 C MAGAZINE 2002年2月号

スタートアップ Ja a Java 言語事始 TabIe 1 java. i0 パッケージにあるストリーム lnputStream BufferedInputStream ByteArraylnputSt 「 eam DataInputStream 8 ビット FiIeInputStream FilterInputSt 「 eam ObjectlnputStream PipedInputStream PushbackInputStream SequencelnputStream Reader BufferedReade 「 Cha 「 Ar 「 ayReader FileReade 「 16 ビット FilterReader InputStreamReader LineNumbe 「 Reade 「 PipedReade 「 PushbackReader St 「 ingReader OutputStream ータを書き出すメソッドです。 w ⅱ te ( ) には , ・ 8 ビット出力 BufferedOutputStream ByteA 「「 ayOutputSt 「 eam ・ 1 6 ビット入力 引数に byte の配列をとるもの , byte の配列 DataOutputStream ・ 1 6 ビット出力 とインデックスをとるもの , int 型 1 個をと FileOutputSt 「 eam るものがあります。みな b e データを出力 ・ランダムアクセスファイル FilterOutputStream ObjectOutputSt 「 eam があり , さらに上記の 4 つには , 入出力先と します。 write(intb) も出力するのは byte デ PipedOutputStream して「ファイル」「パイプ」「ほかのストリー ータ 1 個だけです。 int の下位 8 ビットのみが PrintStream ム」「メモリ」などがそれぞれ用意されてい 出力されます。 Writer るのです ( TabIe 1 ) 。 では , 実際に使ってみましよう。 listl は , BufferedWriter では上記の 4 つを , ファイルへの入出力 0 , 2 , 4 ・・・と , byte データを 10 個ファイル Cha 「 A 「「 ayWrite 「 FileWriter に書き出すものです。やっていることは , を例にして示します。ランダムアクセスフ FilterW 「 ite 「 ァイルはちょっとめんどうな部分があるの ( 1 ) ストリームを生成する OutputStreamW 「 iter ②出力する で , 後でお話しましよう。 PipedW 「 ite 「 P 「 intW 「 ite 「 ( 3 ) ストリームをクローズする ー 8 ビット出力 StringWriter の順序になります。 8 ビット出力は OutputStream に代表され まず生成。 FileOutputStream のコンストラ の」と「出力を担当するもの」があります。 クタはいくつかありますが , ファイル名を ます。 8 ビット入出力のものには末尾に「 St これは当然ですね。そのそれぞれに対して 指定する方法でやっています ( 「ファイル名」 8 ビット単位入出力と 16 ビット文字単位入出 ream 」がつくので覚えておいてください。 を抽象化した File クラスを使う方法もある ) 。 力があります。前述のとおり , 生のデータ メモリ上の配列へ出力する ByteArrayOu このコンストラクタは例外を投げるので , を入出力するものと , 文字の入出力の違い tputStream や java. net. Socket の getOutputStr eam ( ) メソッドの返り値として得られるネ t で囲むかメソッドで throws 宣言するかし です。 C をやった人には「バイナリ入出力」 こでは try 文を使 と「テキスト入出力」といえばわかりやすい ットワークへのストリームがありますが , なければなりません。 こではファイルへの出力を行う FileOu ゆ っています。 かもしれません。 コンストラクタに限らず , 入出力に関す ほかに , 入出力を兼ねるものとして「ラン utStream を参考に使い方を見てみましよう。 る操作の多くは例外を投げます。相手 ( 周 ダムアクセスファイル」があります。まとめ とりあえず , API ドキュメントの Output Stream を見てください。 write() メソッドが 辺機器 ) のあることなので , 失敗の可能性 が常にあるからです。 CD-ROM に書き込も あるでしよう。これがストリームの先へデ List 1 8 ビット出力の例 * OutputStreamSample,java 土 mpo てに扣 va は 0. * clasg OutputStreamSampIe{ public static void main(Stringt] args){ ノ / by に e 型 10 個のデータを用意 取に e [ ] bytes = { 0 , 2 , 4 , 6 , 8 , 10 を 12 , 14 を 16 を 18 / / 書き込むデータを表示 system ・ outeprintln(" 以下のデータを書き込みます”わ for(int 土の土く 1 i 十十 ) { system,out. print(bytes[il + try{ / / ズトリームオブジェクトの生成 OutputStream OS = new FileOutputStream(hbinary. daセ”レ 〃ストリムへ出力 os. write ( bytes リ ノ / ストリームをクローズ os. ose ( }catch( IOException e)( 〃生成か出力でエラーが起きたときの処理 System.err. println( を地工ラーが起きたため正常に出力されませんでしたをリ 。〃終了 System. exit( 1 ) } ッ 出力 、 16 ビット ・ 8 ビット入力 スタートアップ Java / 9

7. 月刊 C MAGAZINE 2002年2月号

EnJOY PerI Programmmg モジュレを活用はう ル中の擬似タグの名前に対応することにな 似タグ TMPL_INCLUDE を見てみましよう。 これらのファイルの中では , TMPL_VA ります。 R の擬似タグが使われています。 List 6(sa これは , 1 つのテンプレートファイルから 出力結果は Fig. 4 のようになります。 TM 別のテンプレートファイルを「取り込む」た mple3head. tmpl) の TMPL—VAR には TODA PL_LOOP の中身が , 繰り返して展開され めの擬似タグです。 C 言語のプリプロセッ Y という名前がついています。これは後で サ命令の # include と似ています。 「今日の日付」に変換されることになります。 ていることがわかりますね。 こでもやは り , HTML はテンプレートファイルの中だ List 5 (sample3. tmpl) は , TMPL—INCLU List 7 (sample3foot. tmpl) の TMPL—VAR に けに書かれています。 DE を使ったテンプレートファイルです。 は COPY Ⅲ GHT という名前がついています PERSON のキーに対応する無名配列のリ TMPL_INCLUDE は 2 か所に使われていま これは著作権表示に変換されることになり ファレンスが含んでいる要素の数が多くな す。 ます。 れば , 自動的に繰り返しの数も多くなります。 この例では , TMPL_INCLUDE を使う意 1 つ目は sampIe3head. tmpl というファイ 実行結果をプラウザで見ると Fig. 5 のよ 義はあまりありませんが , たとえば , 複数 ル , 2 つ目は sample3foot. tmpl というファイ うになります。 ルを取り込むために使われています。 の HTML ファイルを作成する必要があり , List 6 (sample3head. tmpl) と List 7 (sampl そのすべてに「今日の日付」と「著作権表示」 TMPL 」 NCLUDE でファイルの取り込み (sampIe3) e3foot. tmpl) は , 取り込まれている側のテ を同じ形式で埋め込む必要があるとしまし それではもう 1 つ , HTML::TempIate の擬 ンプレートファイルです。 よっ。 TMPL 」 NCLUDE を使ったテンプレートフ アイル (sample3. tmpl) Fig. 5 perl samp 2. p の出力結果をプラウサ で見る 要イル編集、〒盟知こ入リ - ツール . ヘルプ当 アルス 0 名前とメールの対応表 名前 : 村ん Yuki メール : uk [ eom 名前 : 。 m し メール : tom し raOt ・「 -0 名前 : 地新 t 。 メール : 2k0 ね x ⅶ廴 0 鴪 0 く htm l> く head> く title>Sample3 Template く /title> く /head> く bOdY> く hl > 名前とメールの対応表く / hl > <TMPL—INCLUDE NAME="sample3head. tmpl" く table bo て de て = ” 1 ” > <tr> く th> 名前く / th> く th 〉メールく /th> く / して > <TMPL—LOOP NAME="PERSON"> く t て > く td> く TMPL-VAR NAME="NAME"></td> く td> く TMPL—VAR NAME="MAIL"> く /td> く / t て > く / T L ーも </table> く TMPL—INCLUDE NAME=nsampIe3foot.tmpl"> く /bodY> </html> List Fig. 6 perl samp 3. p の出力結果をブラウザ で見る ファイ編 0 、、表示お知ら入りツ—ル、ヘルプ当り ム、印制 名前とメールの対応表 Last u 図 at ・ . F 日一 1019 : 47 2 ( 01 「一名前 ール omura omuraOt ・ fi は 0 を宿よ 22k00 玳 fi 0 ′を 0 ミん / ! 0 2 ( ー 言同ロ 言同ロ をルス ン一を当い一、い匚 0 い ! い第討 ; ・物をいヨ物に朝嶂に , 0 ; 0 ド第 ! 当 44X List TMPL 」 NCLUDE でファイルの取り込み (sample3. pl) use strict ー use 日ル : :Template; # テンプレートの作成 my $template = HTML: :Template->new(filename => 'sample3. tmpl' # 今日の日付け my $today = localtime( # パラメータの設定 $temp late->param ( PERSON = > [ 'Hiroshi Yuki' NAME = 〉 ' hyuki@hyuki.com ' , MAIL = > NAME = 〉 Tomura tomura@textfile.0てg , MAIL = > NAME = > Hanako Sato 'hanako@textfile.org ー MAIL = 〉 TMPL 」 NCLUDE されているテンプレート ファイルその 1 (sample3head. tmpl) Last update : <TMPL—VAR NAME=TODAY> TMPL 」 NCLUDE されているテンプレート ファイルその 2 (sample3foot. tmpl) <address> く TMPL—VAR NAME=COPYRIGHT> </address> List く /P> List TODAY = > に” , COPYRIGHT *> 'Hiroshi Yuki &copy; 2001 ' # 出力 print $temp late->output; 95 Enjoy Perl Programming モシュールを活用しよう

8. 月刊 C MAGAZINE 2002年2月号

W 喩面騰 P 第踟冊 - TID$ 第 25 回 lnternet Exp け er の情報を利用する lnternet Explorer は , さまざまな情報をローカルなハードディスク上に作成しています。今 回は , その情報を得る方法を紹介します。 インターネット上のファイルを比較し , ど PC 内のデータを見ています。初めてのア lnternet Exp 「 e 「の仕組み クセスでは , データをダウンロードする時 ちらが新しいかを判断して , 新しいファイ 間などを含めてそれなりに時間を要します。 ルを見せます。しかしキャッシュはくせ者 で , Fig. 2 のようにインターネットオプシ しかし 2 度目以降のアクセスでは , 極力保 こ数回にわたって , 直接 Web サイト上 存されたデータを表示します。そのため , ョンでこの比較をどうするかを設定できま の HTML ファイル書き換えを実現するアプ す。デフォルトでは「自動的に確認する」に 2 度目以降のアクセスでは非常に高速に We リケーションを取り上げてきました。 CGI なっていますが , 何かの拍子にこの設定を が使えないサイトでも新着ニュースの書き b サイトを表示でき , オフラインでも Web 変更してしまうと , いつも古いファイルを サイトを見ることができます。これがキャ 換えなどが可能になるので , 工ラーチェッ 見ているなどの現象が起こります。 クなどを含めてしつかり再構築すれば , 使 ッシュの仕組みです。 このことからわかるように , Web サイト えるアプリケーションになるでしよう。 クッキーとは へのアクセスを重ねていくと自然にハ 今回は少し視点を変え , 利用するユーザ クッキーとは , アクセスしたユーザの情 ディスク内にデータがたまります。そこで , 側の利便性を図ってみます。 報を WWW サーバや Web サイトごとにロー lnternet Explorer では Fig. 1 のようにインタ キャッシュの仕組み ーネットオプションの「インターネットー カルなファイルとして保存する機能です。 時ファイル」の⑧ ] で , キャッシュファ ューザ情報がハードディスク内に保存され web プラウザは , 直接インターネット上 ることがポイントです。たとえばサイトへ イルの削除やハードディスクの使用容量を のデータを見るのではなく , HTML ファイ のアクセス者を限定したい場合に , どのよ ルだけでなく GIF や JPEG などの画像ファイ 制限できます。 うな方法が考えられるでしようか ? ルも含めて , ダウンロードして保存された Web プラウザは , キャッシュファイルと Fig. 2 保存しているべージの新しいバージョンの確認 Fig. 1 インターネット一時ファイルの設定 tatsuya (tatsuya@exnetcom.com) インターネットオプション 定 全般ーセキュリテ新コンテンツー接続ープロ乃ムい羊細設定ー ホームページ ホームページとして使用するべージは変更できます。 アドレス⑧・ インターネット一時万イルーー インターネットで表示したべージは持別なフォルダに保存され、冫大回カ汚は 0 短時問で表不で・きます。 ージへのリンクが含まれます。これを使用す へすはやくアクセスできます。 ペを履歴に保存する日数 ( 0 国一ヨ、 - ! 2 旦 - 」 ユーサー補助 ( 印」 保存しているべージの新いトジョンの確認 . 0 ペラを表示することに確認する ) 0 印 Explorer を起動するごとに確認する 礙る四 0 確認しない型 ) インタネット一時ファイ ) しのフォ丿隊 現在の場所 0 : ¥ Docu ments 記 Settings%Adm ⅶ引 t ¥ LOC 引 Settings*Temporary lnternet F iles* 使用するディスク領域 0 : 557 ュ些些生」ュ ! 凹塹些」堡 : : 」 亠ー当ーー」キャンセルー適・朋 ) ー 140 C MAGAZINE 2002 2

9. 月刊 C MAGAZINE 2002年2月号

lSt 3 : 6 : 8 : 9 : 10 : 12 : 13 : 16 : 18 : { 19 : 20 : 21 : 22 : 23 : 24 : 26 : 28 : 29 : 30 : 31 : 32 : 33 : 34 : 35 : 36 : 37 : 38 : 39 : 40 : 41 : 42 : 43 : 44 : 45 : 46 : 48 : 50 : 51 : 52 : 53 : 54 : 55 : 56 : 57 : } 59 : { 60 : 61 : 62 : 63 : 64 : 65 : 66 : 67 : 68 : 69 : 70 : 71 : 72 : 73 : 74 : 75 : 76 : 77 : 78 : 79 : 80 : 81 : 82 : 83 : 84 : 86 : } 87 : 89 : 90 : 92 : 93 : 94 : ランダムアクセス処理の例 List 1 1 : #include <stdio. h> #include く std は b. れ〉 #include く string. h> 5 : / * 構造体の宣言 * / struct c liant { char name[30]; char te Ⅱ 12 }dataW ー 11 : FILE *fp; int DataOutput ( void 土れ t DataChange(void) ・ 14 : int DataDispAII (VOid5; 17 : int main( ) / * 1 : 画面から入力したデータをファイルへ書き出す * / / * 2 : 指定したデータを更新する * / / * 3 : ファイルから全データを読み込み画面へ出力する * / 15 : int DataDispSeIec(void); / * 4 : ファイルから指定データを読み込み画面へ出力する * / 。 int iret ー char buf [ 1024 ] = while (buf[0J ! = ' ー / * 画面からの入力バッファ * / puts( ″ = = = 顧客管理メニュ puts(" 1 . データ入力″ puts(" 2 . レコードの書き換え ( レコード指定 ) ″ puts(" 3 . データの表示 ( 全データ ) ″ puts(" 4 . データの表示 ( レコード指定 ) 新 prin し f ( 、 n 処理を選択してください = 〉” 5 . 終了” puts に break ・ defau 比 : break; case ' 5 break ・ if (iret く 0 ) return - 場 iret = DataDispSe lec ( case ' 4 break ・ if (iret く 0 ) return - 辷 e し = DataDispAII ( case ' 3 break ・ if (iret く 0 ) return - iret = DataChange( case ' 2 if ( iret く 0 ) return ー iret=DataOutput ( case ' 1 ' switch(buf[0] ) ( gets(buf); puts(" ! ! 入力番号が不正です。 95 : 96 : 98 : 99 : 100 : 101 : 102 : 103 : 104 : 105 : 106 : 107 : 108 : 109 : 110 : 111 : 112 : 113 : 114 : 115 : 116 : 117 : 118 : 119 : 120 : 121 : 122 : 123 : 124 : 125 : 126 : 127 : } 128 : 129 : { 130 : 131 : 132 : 133 : 134 : 135 : 136 : 137 : 138 : 139 : 140 : 141 : 142 : 143 : 144 : 145 : 146 : 147 : 148 : } 150 : { 151 : 152 : 153 : 154 : 155 : 156 : 157 : 158 : 159 : 160 : 161 : 162 : 163 : 164 : 165 : 166 : 167 : 168 : 169 : 170 : 171 : 172 : 173 : 174 : 175 : 176 : 177 : 178 : 179 : 180 : 181 : 182 : 183 : int puts(" 「 1 . データ入力」を実行してみてください。心 n ” / * 続行可能 * / while(l) ( return 1 ー 辷 e セ fseek(fp, RecNo*sizeof(dataW) , 'SEEK-SET)Y strncpy(dataw. にeし buf, 12 gets ( buf printf( n 新しい電話番号 : ” strncpy(dataW. name, buf, 30 gets(buf); printf("%n 新しい名前 : ” RecNo = atoi(buf) - puts に 1 ~ 3 までを入力してください。つ = の break; strcmp(buf, ” 3 ” ) = 0 Ⅱ strcmp(buf, ″ 2 つ = if(strcmptbuf, " 1 つ gets(buf) ・ printf ( 、 n 変更対象のレコード番号を入力してください = ” return -1 ー fclose(fp); puts(" ! て土 te e てて 0 て ! ! ” return -1 ー puts( ” ! !fseek error! に if(iret) { int DataDispAll ( ) return 0 ー fcl ose ( fp if(fwrite(&dataw, 1 , sizeof(dataw) , (p) = = 0 ) { puts(" 「 1 . データ入力」を実行してみてください。跏 n ” puts( ファイルがオープンできません。” if( (fp=fopen( "FILEII. d" / * ファイルオープン ( 入力モード ) * / printf( n 阯宅 6s ト 30. 30S 基 t 6s 宅ー 12.12S \ n ” return - fclose(fp); puts( ″ ! !read e てて or ! ! ” if(fread(&dataw, 1 , sizeof(dataw) , fp) for ( 辷の長 3 ・ i 十十 ) { return / * 続行可能 * / ”名前 : ",dataW. name," 電話 :",dataw. t引嶹 break; return 0 ー 58 : 土 n し DataOutput( ) fcl ose ( fp return 149 : int DataDispSeIec( ) int iret , RecNo ー char buf[10241; / * 画面からの入力バッファ * / int char buf [ 1024 / * 画面からの入力バッファ * / / * ファイルのオープン ( 以前のデータをクリア ) * / if( (fp=fopen( 。 FI 11. d 。 ,"wb") ) = = L い { puts( ! !write-file open error ! ! ″ return -1 ー puts に 3 人分の名前、電話番号を入力してください。 return -1 ー fclose(fp); puts に ! ! write er て 0 て ! ! ” if(fwrite(&dataw, 1 , sizeof(dataW) , (p) = = 0 ) { / * シーケンシャルに書き出す * / strncpy(dataw. tel, buf, 12 gets(buf); printf("%n 電話番号 : "); strncpy(dataw. name, buf, 30 gets(buf); printf( ” n 名前 : ” for (i=0; i く i 十十 ) { 土 n し fc lose ( fp return 0 ー DataChange( ) int RecNo, iret; char buf [ 1024 / * 画面からの入力バッファ * / 184 : 185 : } / * ファイルのオープン ( 追加モード ) * / if( (fp=fopen( ″ FI も E11. d ″ , を b + つ )==NULL) { p 此 s ( ″ファイルがオープンできません。″ / * ファイルオープン ( 入力モード ) * / if( (fp=fopen("FILE11. d" puts ( ”ファイルがオープンできません。″ puts(" 「 1 . データ入力」を実行してみてください。蕚 n ″ return / * 続行可能 * / while(l) { 'iret ゴ fseek(fp, RecNo*sizeof(dataW) / SEEK—SET)} RecNo = atoi(buf) - puts( ” 1 ~ 3 までを入力してください。” ) ・ = 0 ) break; strcmp(buf, ” 3 ” ) = 0 Ⅱ strc 叩 (buf, ” 2 つ = if(strcmp(buf, ” 1 つ gets ( buf p て intf ( 、 n 表示したいレコード番号を入力してください = > ” ”名前 : ",dataw. name," 電話 :",dataw. t引リ printf( ”基 n 基し 6s 宅 -30.30S 基 t 6s ー 12.12S 基 n ” 0 return -1 ー fclose(fp); puts()! !read e てて or ! に if(fread(&dataW, 1 , sizeof(dataW) , (p) = = 0 ) ( return -1 ー puts()l !fseek e てて 0 て ! に if(iret) { return 0 ー fcl ose ( fp 式は使用しません。本来リスト構造は , メ ( 5 ) 任意の時点で , 現在登録されている すべてのデータをクリアできる ( 6 ) 任意の時点で , 現在登録されたデー 順に表示される このプログラムのメニュー画面を Fig. 4 に示します。 このプログラムではランダムアクセス方 モリ上で追加 , 更新 , 削除といった処理を 行うからです。ファイルからの読み込み時 はすべてのノードを読み込み , メモリ上に 70 タを表示できる。このとき出席番号 C MAGAZINE 2 2 2

10. 月刊 C MAGAZINE 2002年2月号

lSt 27 : } / 2 1St 2 : 4 : 5 : 6 : 8 : 9 : 10 : 11 : 12 : 13 : 14 : 15 : 16 : 17 : 18 : 19 : 20 : 21 : 22 : 23 : 24 : 25 : 26 : 28 : 29 : 30 : 1St 4 : 5 : 6 : 7 : 8 : 9 : 10 : 11 : 12 : 13 : 14 : 15 : 16 : 17 : 18 : 19 : 20 : 21 : 22 : 24 : 25 : 26 : 28 : 29 : 30 : 31 : 32 : 33 : 34 : 35 : 36 : 38 : 39 : 41 : 42 : 44 : 45 : 46 : 48 : 49 : 50 : 51 : 52 : 53 : 54 : 55 : 56 : 57 : } pcurrent = getfield( while(l) { return 1 ー p て in ( t 入力ファイルがオープンできません . は s ] % FileName); if()p = NULL) { fp = fopen(FiIeName, を b ” C learList ( / * 現在のデータを初期化する struct Student *pCurrent ー int len ー FILE *fp; int ReadListData ( char *Fi leName ) 1 : / * 指定のファイル名よりリストを読み込む * / ファイルからの読み込み ファイルへの出力 2 : 4 : 5 : 6 : 7 : 8 : 10 : 11 : 12 : 13 : 14 : 15 : 16 : 17 : 18 : 19 : 20 : 21 : 22 : 24 : 25 : 26 : 1 : / * 指定のファイル名にリストを書き込む int WriteListData ( char *Fi ー eName ) FILE *fp; 土北 len ー struct Student *pCurrent ー if(fp== NULL) { return pCurrent = pStart → Next; whil e ( pCurrent ) { len = fread ( pcurrent, sizeof ( struct Student ) , if(len = = 0 ) { if(feof(fp)) break; / * E 0 F で終了 * / pu セ s ( ”齔ファイルが読めません . ” else { 2 : 土 n し InsertNode ( void ) 1 : / * 入力データを追加、修正する ノードの登録・修正 return 0 ー fc lose ( fp pEnd = pCurrent; pCurrent->Next = NULL ・ pEnd->Next = pCurrent; return 1 ー 1 ′ fp); char buf [ 1024 struct Student stdnt , *EEurrent ー pri 北 f ( n 阯阯出席番号 : ” gets(buf); stdnt.code = atoi(buf) ・ printf( ″基 t t 名前 : ″ gets(buf); *pNew; strncpy(stdnt. name, buf, sizeof(stdnt. name) printf( t 国語 : ″ gets(buf); stdnt.tensuu. kokugo = atoi(buf); if(stdnt. tensuu. kokugo > 100 ) stdnt. if(stdnt.tensuu. kokugo く 0 ) printf("%t%t 算数 : ” gets(buf); stdnt. tensuu. sansu atoi(buf); if(stdnt . tensuu. sansu > 100 ) if ( stdnt . tensuu. sansu く 0 ) printf( ″阯英語 : ” gets(buf); stdnt. tensuu. eigo atoi ( buf stdnt. stdnt . tensuu. stdnt. tensuu. tensuu tensuu . tensuu . kokugo = 10 kokugo = . sansu = 10 tensuu. sansu = 0 ・ . eigo = 10 の eigo = if(stdnt.tensuu. eigo > 100 ) if(stdnt.tensuu. eigo く 0 ) / * 挿入位置を決定 * / pCurrent = pStart; while(pCurrent->Next) { stdnt. stdnt if(pCurrent->Next → code = = stdnt.code) stdnt. Next = EÆurrent->Next → Next ー *pCurrent->Next = stdnt; return 0 ー if(pcurrent → Next->code > stdnt. code) break ー pCurrent = pCurrent->Next ー / * pp て i 。ての次に新たなノードを作成して挿入する * / / * 次のノードへ移動 * / / * 次の出席番号が大きい時 * / / * 上位へ復帰 / * 入力データと置き換える * / / * 次へのポインタをコピー * / / * は置き換えて終了 / * 同一番号が存在する場合 * / ( / * 出席番号をチェック pEnd ま pNew; if(pEnd = = pCurrent->Next = pNew ー *pNew = stdnt; stdnt. Next = pCurrent->Next ー return 1 ー puts ( ”メモリが確保できません . ″ if(pNew = NULL) { pNew = getfield( / * 最終位置に追加した場合は p 新 d を更新 * / return 0 ー p て intf ( " 阯出力ファイルがオープンできません . 締 s 兤 n % FiIeName); pCurrent = pCurrent->Next; return 1 ー fclose(fp); u セ s ( ”ファイルに出力できません . ” ); if (len = 0 ) { len = fwrite(pCurrent, sizeof(struct student) , 1 , fp); return の fc lose ( fp g. 6 の要領で削除します田 st6 ) 。 前のノードの情報を検索し , 見つかれば Fi データの削除も , 登録・修正と同様に 1 つ 内部関数 DeleteNode として実装します。 データの削除 処理できます (List5)0 ノードと出席番号を判定すれば , 都合よく (Fig. 5 ) 。これを実現するには常に 1 っ先の 前のノードのアドレスが必要となります xt が NULL のとき ) 。つまり挿入位置の 1 つ た場合は , 最終ノードの次となります (Ne るいはもっとも大きな出席番号が入力され 大きなものの前ということになります。あ す。挿入位置は , 入力された出席番号より になるような位置に挿入することになりま リスト上に存在しない場合は , 出席番号順 があれば , これを置き換えて終了します。 出席番号が入力されたものと同じノード を用意してリストをたどります。 理中のノードを指すポインタ変数 pCurrent udent 構造体の実体を確保します。現在処 画面からの入力データを保存するため , St 内部関数 InsertNode として実装します。 データの登録・修正 力します (List 4 ) 。 書き込みもリストに登録されている順に出 データが連結されています。ファイルへの C MAGAZINE 2 2 2