(10)06/22の授業内容
- openメソッド
- openメソッドを使ったファイルへの書き込み
- openメソッドを使ったファイルからの読み込み
前回のプログラムは,ファイルから1行ずつ読み込み特定の処理をおこなうものでした.ファイルの指定は,プログラムを実行する際に具体的にscore.txt入力することで行われていました.しかし,常に同じファイルを読み込むのであればこのような指定は面倒です.また場合によってはデータを読み込むのではなく,データを書き出すということもありえます.このような場合に利用するのがopenメソッドです.様々な使い方がありますが,以下の方法を把握しておけばよいでしょう
open("ファイル","モード")do |変数| ファイルを読み込んで行う処理 end
ファイル:開きたいファイル名を指定します.ファイルがプログラムと同一ディレクトリにある場合は,単にファイル名を指定するだけでよいですが,異なるディレクトリにある場合には../data.txtのようにパス指定をする必要があります
モード:開いたファイルを読み込みたいのか,書き込みたいのか,新規作成したいのかなどの用途によりモードは異なります.6種類あります
r:読み込み専用
r+:読み込み/書き込用
w:書き込み専用.当該ファイルが存在しない場合には新規作成し,存在する場合はそのデータを全て削除して新しくファイルを作成する
w+:読み込み/書き込み用で,その他はwと同じ
a:追加書き込み専用.当該ファイルが存在しない場合は新規作成するが,存在する場合はデータの末尾に続けて書き込みを行う
a+:読み込み/追加書き込み用で,その他はaと同じ
変数:開いたファイルからの読み込みや,開いたファイルへの書き込みを行う際に使うもので,任意の名前でよい
ファーストフードのPOSを想定したプログラムを作ります.POSは会計を行うのみでなく,在庫管理や販売戦略の分析にも利用できるものです.ここでは,お会計の際に客層を入力することで,客層別の人数と客単価を表示できるプログラムを作っています.下記はデータ入力用のプログラムで,お会計を行うことで,客層と,ハンバーガー,ドリンク,アップルパイの購入金額をpos_data.outという名前のファイルに書き込みます.pos_input.rbという名前をつけて保存し,実行してみましょう.
実行したらktermでcat pos_data.out[Retern]と入力すると,書き込まれたデータを見ることができます(ちなみにpos_data.outを削除するときのコマンドはrmで,rm pos_data.out[Return]と入力します)
#!/usr/koeki/bin/ruby burger = 0 #ハンバーガーの金額 drink = 0 #ドリンクの金額 pie = 0 #アップルパイの金額 i = 0 #配列に代入する際のインデックス sum = 0 #合計金額 open ("pos_data.out", "a") do |pos| while true STDERR.print "客層の選択(1:学生、2:会社員、3:ファミリー、9:営業終了):" customer = gets.chomp!.to_i if customer == 9 then STDERR.print "本日の営業は終了しました\n" break end STDERR.print "ハンバーガーはいかがでしょうか(金額を入力):" burger = STDIN.gets.chomp!.to_i STDERR.print "お飲み物はいかがでしょうか(金額を入力):" drink = STDIN.gets.chomp!.to_i STDERR.print "ただいまアップルパイが100円になっております(y or n):" a = STDIN.gets.chomp! if a == "y" pie = 100 else pie = 0 end sum = burger + drink + pie STDERR.printf "お会計%d円になります。どうもありがとうございました\n", sum pos.printf "%d \t %d \t %d \t %d\n", customer, burger, drink, pie i += 1 STDERR.print "\n" STDERR.print "お次のお客様どうぞ\n" end end
新しく出てきた部分について説明します
open ("pos_data.out", "a") do |pos|
pos_data.outというファイルを開きます.モードは"a"なので追加書き込み専用です.一番最初に実行した場合は,pos_data.outは存在しないので新規作成されますが,何度か繰り返し実行すると既存のpos_data.outの末尾に実行結果が追加で書き込まれます.なおposはpos_data.outに書き込みを行う際の変数として指定しています
pos.printf "%d \t %d \t %d \t %d\n", customer, burger, drink, pie
通常のprintfにpos.がついています.posは書き込みを行う際の変数として指定されたものです.pos.printfとすることでディスプレイではなく,ファイルに対して表示(=書き込み)が行われます.実行をしてもディスプレイに何も表示されないのはprintfではなくpos.printfとなっているためです.なお""内の\tはタブの意味でスペースを空けるという意味です.キーボードのTabキーと同じ働きです
STDIN(標準入力)とSTDERR(標準エラー出力)
ファイルを指定した場合,getsメソッドはキーボードからの読み込みと,ファイルからの読み込みが可能になります.またprintやprintfメソッドはディスプレイへの表示,ファイルへの書き込みが可能になります.このためこれらのメソッドを使用する際にはどこから読み込むのか,どこへ出力するのかを指定しないと,思ったような結果にならないことがあります
ファイルからの読み込み,ファイルへの書き込みを行う場合にはpos.gets, pos.print, pos.printfのようにファイルをopenしたときに指定した任意の変数をつけます.一方ディスプレイへの表示の場合はSTDERR.print,STDERR.printf,キーボードからの入力はSTDIN.getsをつける必要があります.
次は,書き込まれたpos_data.outを読み込んで,客層別の人数と客単価を表示するプログラムです.pos_analysis.rbと名前をつけて保存し,実行してみよう
#!/usr/koeki/bin/ruby student_sum = 0 #学生の購入金額 worker_sum = 0 #会社員の購入金額 family_sum = 0 #ファミリーの購入金額 student_count = 0 #学生の人数 worker_count = 0 #会社員の人数 family_count = 0 #ファミリーの組数 open ("pos_data.out", "r") do |pos| while line = pos.gets if /(\w)\s+(\w+)\s+(\w+)\s+(\w+)/ =~ line if $1.to_i == 1 #客層が「学生」の場合 student_sum += $2.to_i + $3.to_i + $4.to_i student_count += 1 elsif $1.to_i == 2 #客層が「会社員」の場合 worker_sum += $2.to_i + $3.to_i + $4.to_i worker_count += 1 else #客層が「ファミリー」の場合 family_sum += $2.to_i + $3.to_i + $4.to_i family_count += 1 end end end end print "\n" printf "学 生は%2d人,売り上げ合計は%6d円,客単価は%5d円です\n", student_count, student_sum, student_sum/student_count printf "会社員は%2d人,売り上げ合計は%6d円,客単価は%5d円です\n", worker_count, worker_sum, worker_sum/worker_count printf "家 族は%2d組,売り上げ合計は%6d円,客単価は%5d円です\n", family_count, family_sum, family_sum/family_count
新しく出てきた部分について説明します
open ("pos_data.out", "r") do |pos|
今度はモードrで開いています.rは読み込み専用の意味です
while line = pos.gets
pos.getsとすることでpos_data.outから1行ずつ読み込みlineに代入します
なおpos_input.rbとpos_analysis.rbは合体して1つのプログラムとすることもできます(pos_analysis.rbの先頭の#!usr/...の部分のみ消去).つまり,1つのプログラムの中でファイルを何度も閉じたり開いたりすることができます.実際に合体し,pos.rbという名前をつけて保存し実行してみよう
課題
以下の3つから1つを選んで実施する.1は8点満点,2は9点満点,3は10点満点で採点する
- pos.rbを改良する.下記のリストのうち1つ選んで実施する
- pos.rbを改良する.下記のリストのうち3つ選んで実施する
- 客層を「学生」「会社員」「ファミリー」から「高校生」「大学生」「会社員」「ファミリー」に変更する(pos_input.rb部の最初の方や,pos_analysis.rb部のif部,printf部の修正が必要)
- 最後のprintf部で,人数,売上合計,客単価を表示するのではなく,人数,売り上げ合計,ハンバーガーの平均売上額,飲み物の平均売上額,アップルパイの平均売上額,客単価を表示するように変更する(pos_analysis.rb部のif部,printf部を修正する.客層別にハンバーガー,飲み物,アップルパイの売上合計を求め,人数で割って平均値を算出する)
- ハンバーガーや飲み物の注文を受ける際,金額を入力するのではなく,1.ハンバーガー,2.コロッケバーガー,3.スーパーウルトラグレートバーガーのように選択肢から選べるように変更する(変更方法はアップルパイを参考にすればよい)
- ハンバーガー,飲み物,アップルパイの3つのカテゴリを,例えば,ハンバーガー,飲みもの,アップルパイ,ポテトのように4つ以上のカテゴリにする(いろいろと細かい変更が必要)
- pos.rbを改良する.上記のリストのうちの3を実施したうえで,下記の変更も行う.それ以外にも自由に変更を加えてよい
リスト
「さっきハンバーガーと言ったけれど,やっぱりコロッケバーガー」というような注文に対して対応できるようにする.具体的には「以上でよろしいでしょうか」というメッセージを出し,よろしくない場合に注文を取り直す(入力した金額を修正する)ことができるようにする(この際,ハンバーガー,飲み物,アップルパイ全てを最初から入力しなおすように修正しても良いし,一部だけ修正できるように変更しても良い.やり方は様々なのでヒントはなし)
作成したプログラム,実行結果をメールでnaoya@e.koeki-u.ac.jp宛に送る.
課題の提出期限は6月25日(土)17:00まで
メール送信時の注意
- Subjectは「学籍番号-kadai8」とすること
- 本文の1行目ではまず名乗ること
- 2行目以降は下記の構成で記載すること
- 作成したプログラム
- プログラムの説明
- 実行結果
- 感想
今回は作成したプログラム,プログラムの各部の説明に同じウェイトをおいて評価します(説明は,変更した部分,今回新しく出てきた部分について行ってください.もちろん全て行っても構いません)
Tips
emacsについて
- emacsで新しいファイルを作成する場合は,C-x C-fを押し,ミニバッファにkensaku/kadai2.rbのようにファイル名を入力する
- ファイルの保存はC-x C-s
- 日本語入力のオンオフの切り替えはC-o
Mewについて
- emacsを起動する
- Escとxを押し,mewと入力しReturn(Escとxを押すことを,一般にM-xと表記します)%<--これでMewが起動します
- Mewを起動するとパスワードがたずねられるので入力しReturn
- 新着メールの確認およびパスワードを間違えた場合はiと入力しReturn
- メールを読む場合は,カーソルキー(矢印キー)で読みたいメールを選びReturn
- メールの新規作成はwと入力
- e-mailの本文にテキストファイルを読み込むには,新規送信メール画面の本文を記入するエリアにカーソルを移動し,Ctrl+x,iとすると,ミニバッファにInsert file: ~/と表示されるので,読み込みたいファイル名を入力する。
- プログラムの実行結果の貼り付けは,kterm上の出力結果部分をマウスで選択し,Mewの本文の貼り付け位置にカーソルを移動し,マウスの真ん中ボタンをクリックする
- メールの送信はC-c C-cと入力するか,もしくはメニューのsendアイコンをクリックする
- Mewを終了するにはqと入力
- emacsを終了する