blog/content/post/2011/04/02/2011-04-02-00001465.md

233 lines
14 KiB
Markdown

---
title: ファイルの読み書き
author: kazu634
date: 2011-04-02
wordtwit_post_info:
- 'O:8:"stdClass":13:{s:6:"manual";b:0;s:11:"tweet_times";i:1;s:5:"delay";i:0;s:7:"enabled";i:1;s:10:"separation";s:2:"60";s:7:"version";s:3:"3.7";s:14:"tweet_template";b:0;s:6:"status";i:2;s:6:"result";a:0:{}s:13:"tweet_counter";i:2;s:13:"tweet_log_ids";a:1:{i:0;i:5421;}s:9:"hash_tags";a:0:{}s:8:"accounts";a:1:{i:0;s:7:"kazu634";}}'
categories:
- gauche
---
<div class="section">
<p>
Gaucheでファイルの読み書きをする場合の処理を作成してみました。
</p>
<h4>
作成する処理について
</h4>
<p>
こんなのをイメージして作ったよ。
</p>
<h5>
読み書きするファイルのフォーマット
</h5>
<p>
読み書きするファイルのフォーマットとして以下を想定したよ:
</p>
<ul>
<li>
1行目に日付データ(エポックタイム)
</li>
</ul>
<p>
例えばこのようになります:
</p>
<pre class="syntax-highlight">
% cat <span class="synStatement">test</span>.dat
<span class="synConstant">1234567890</span>%
</pre>
<h5>
読み込む処理
</h5>
<p>
こんなのを想定しました:
</p>
<ol>
<li>
ファイルが存在しなければ #f を返す
</li>
<li>
ファイルが存在すれば、一行目を読み込む
</li>
<li>
読み込んだ文字列を数値形式に変換し、数値形式の値を返す
</li>
<li>
数値形式に変換できなければ、 #f を返す
</li>
<li>
2行目以降は無視する
</li>
</ol>
<h5>
書き込む処理
</h5>
<p>
こんなのを想定しました:
</p>
<ol>
<li>
ファイルが存在しなければ、ファイルを作成してデータを書き込む
</li>
<li>
ファイルが存在する場合は、上書きする
</li>
<li>
書きこむデータとして与えられたのが数値であれば、数値として書きこむ
</li>
<li>
書きこむデータとして与えられたのが文字列であれば、文字列として書き込む
</li>
<li>
それ以外であれば、 #f を返す
</li>
</ol>
<h4>
作成したソース
</h4>
<p>
作成したソースはこんな感じ:
</p>
<pre class="syntax-highlight">
#!/usr/bin/env gosh
<span class="synComment">;;; unit.test</span>
<span class="synSpecial">(</span>use gauche.test<span class="synSpecial">)</span>
<span class="synComment">;;; ファイルからの読み取り</span>
<span class="synSpecial">(</span>define <span class="synSpecial">(</span>read-data-from-file path2file<span class="synSpecial">)</span>
<span class="synSpecial">(</span>with-input-from-file path2file
<span class="synSpecial">(</span><span class="synStatement">lambda</span> <span class="synSpecial">()</span>
<span class="synSpecial">(</span>let1 <span class="synConstant">1</span>stline <span class="synSpecial">(</span><span class="synStatement">read-line</span><span class="synSpecial">)</span>
<span class="synSpecial">(</span>string-&#62;number <span class="synConstant">1</span>stline<span class="synSpecial">)))</span>
<span class="synType">:if-does-not-exist</span> #f<span class="synSpecial">))</span>
<span class="synComment">;;; ファイルへの書き込み</span>
<span class="synSpecial">(</span>define <span class="synSpecial">(</span>write-data-from-file path2file data<span class="synSpecial">)</span>
<span class="synSpecial">(</span>call-with-output-file path2file
<span class="synSpecial">(</span><span class="synStatement">lambda</span> <span class="synSpecial">(</span>port<span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synStatement">cond</span>
[<span class="synSpecial">(</span><span class="synStatement">number</span>? data<span class="synSpecial">)</span> <span class="synSpecial">(</span>begin
<span class="synSpecial">(</span><span class="synStatement">format</span> port <span class="synConstant">&#34;~D&#34;</span> data<span class="synSpecial">)</span>
#t<span class="synSpecial">)</span>]
[<span class="synSpecial">(</span><span class="synStatement">string</span>? data<span class="synSpecial">)</span> <span class="synSpecial">(</span>begin
<span class="synSpecial">(</span><span class="synStatement">format</span> port <span class="synConstant">&#34;~A&#34;</span> data<span class="synSpecial">)</span>
#t<span class="synSpecial">)</span>]
[else #f]<span class="synSpecial">))</span>
<span class="synType">:if-does-not-exist</span> <span class="synType">:create</span><span class="synSpecial">))</span>
<span class="synComment">;;; test starts</span>
<span class="synSpecial">(</span>test-start <span class="synConstant">&#34;ファイルの読み書き&#34;</span><span class="synSpecial">)</span>
<span class="synComment">;;; 設定ファイルからの読み込み</span>
<span class="synSpecial">(</span>test-section <span class="synConstant">&#34;ファイルからの読み込み&#34;</span><span class="synSpecial">)</span>
<span class="synSpecial">(</span>test* <span class="synConstant">&#34;ファイルの1行目を読み込む&#34;</span>
<span class="synConstant">1234567890</span>
<span class="synSpecial">(</span>read-data-from-file <span class="synConstant">&#34;./test.dat&#34;</span><span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synStatement">lambda</span> <span class="synSpecial">(</span>expected result<span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synStatement">=</span> expected
result<span class="synSpecial">)))</span>
<span class="synComment">;;; 設定ファイルへの書き込み</span>
<span class="synSpecial">(</span>test-section <span class="synConstant">&#34;設定ファイルへの書き込み&#34;</span><span class="synSpecial">)</span>
<span class="synSpecial">(</span>test* <span class="synConstant">&#34;数値をファイルへ書き込む&#34;</span>
#t
<span class="synSpecial">(</span>write-data-from-file <span class="synConstant">&#34;./test.dat&#34;</span>
<span class="synConstant">1234567890</span><span class="synSpecial">))</span>
<span class="synSpecial">(</span>test* <span class="synConstant">&#34;数値が正常に書きこまれていることを確認する&#34;</span>
<span class="synConstant">1234567890</span>
<span class="synSpecial">(</span>read-data-from-file <span class="synConstant">&#34;./test.dat&#34;</span><span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synStatement">lambda</span> <span class="synSpecial">(</span>expected result<span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synStatement">=</span> expected
result<span class="synSpecial">)))</span>
<span class="synSpecial">(</span>test* <span class="synConstant">&#34;文字列をファイルへ書き込む&#34;</span>
#t
<span class="synSpecial">(</span>write-data-from-file <span class="synConstant">&#34;./test.dat&#34;</span>
<span class="synConstant">&#34;1234567890&#34;</span><span class="synSpecial">))</span>
<span class="synSpecial">(</span>test* <span class="synConstant">&#34;文字列が正常に書きこまれていることを確認する&#34;</span>
<span class="synConstant">1234567890</span>
<span class="synSpecial">(</span>read-data-from-file <span class="synConstant">&#34;./test.dat&#34;</span><span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synStatement">lambda</span> <span class="synSpecial">(</span>expected result<span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synStatement">=</span> expected
result<span class="synSpecial">)))</span>
<span class="synSpecial">(</span>test-section <span class="synConstant">&#34;異常系&#34;</span><span class="synSpecial">)</span>
<span class="synComment">;;; 設定ファイルを一時削除する</span>
<span class="synSpecial">(</span>sys-unlink <span class="synConstant">&#34;./test.dat&#34;</span><span class="synSpecial">)</span>
<span class="synSpecial">(</span>test* <span class="synConstant">&#34;ファイルが存在しない場合は読み込み処理は #f を返す&#34;</span>
#f
<span class="synSpecial">(</span>read-data-from-file <span class="synConstant">&#34;./test.dat&#34;</span><span class="synSpecial">))</span>
<span class="synSpecial">(</span>test* <span class="synConstant">&#34;エポックタイム形式以外のデータを書き込む&#34;</span>
#t
<span class="synSpecial">(</span>write-data-from-file <span class="synConstant">&#34;./test.dat&#34;</span>
<span class="synConstant">&#34;123456789a&#34;</span><span class="synSpecial">))</span>
<span class="synSpecial">(</span>test* <span class="synConstant">&#34;エポックタイム形式以外のデータを読み込んだ場合は #f を返す&#34;</span>
#f
<span class="synSpecial">(</span>read-data-from-file <span class="synConstant">&#34;./test.dat&#34;</span><span class="synSpecial">))</span>
<span class="synComment">;;; 設定ファイルを一時削除する</span>
<span class="synSpecial">(</span>sys-unlink <span class="synConstant">&#34;./test.dat&#34;</span><span class="synSpecial">)</span>
<span class="synSpecial">(</span>test* <span class="synConstant">&#34;ファイルが存在しない場合は、書き込み処理はファイル作成して #t を返す&#34;</span>
#t
<span class="synSpecial">(</span>write-data-from-file <span class="synConstant">&#34;./test.dat&#34;</span>
<span class="synConstant">1234567890</span><span class="synSpecial">))</span>
<span class="synSpecial">(</span>test* <span class="synConstant">&#34;正常に書きこまれていることを確認する&#34;</span>
<span class="synConstant">1234567890</span>
<span class="synSpecial">(</span>read-data-from-file <span class="synConstant">&#34;./test.dat&#34;</span><span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synStatement">lambda</span> <span class="synSpecial">(</span>expected result<span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synStatement">=</span> expected
result<span class="synSpecial">)))</span>
<span class="synSpecial">(</span>test-section <span class="synConstant">&#34;現状復帰&#34;</span><span class="synSpecial">)</span>
<span class="synSpecial">(</span>test* <span class="synConstant">&#34;データファイルの回復&#34;</span>
#t
<span class="synSpecial">(</span>write-data-from-file <span class="synConstant">&#34;./test.dat&#34;</span>
<span class="synConstant">&#34;1234567890&#34;</span><span class="synSpecial">))</span>
<span class="synSpecial">(</span>test-end<span class="synSpecial">)</span>
</pre>
<p>
実際に実行する場合は、事前にテストデータを作成してください。こんな感じです:
</p>
<pre class="syntax-highlight">
% <span class="synStatement">echo</span><span class="synConstant"> </span><span class="synStatement">&#34;</span><span class="synConstant">1234567890</span><span class="synStatement">&#34;</span><span class="synConstant"> </span><span class="synStatement">&#62;</span> <span class="synStatement">test</span>.dat
</pre>
<h4>
実行結果
</h4>
<p>
実行するとこんな風になります:
</p>
<pre class="syntax-highlight">
% ./<span class="synConstant">2011-04-02-161017</span>.scm
Testing ファイルの読み書き ...
<span class="synStatement">&#60;</span>ファイルからの読み込み<span class="synStatement">&#62;</span>------------------------------------------------------------------
<span class="synStatement">test</span> ファイルの<span class="synConstant">1</span>行目を読み込む, expects <span class="synConstant">1234567890</span> <span class="synStatement">==&#62;</span> ok
<span class="synStatement">&#60;</span>設定ファイルへの書き込み<span class="synStatement">&#62;</span>-----------------------------------------------------------------
<span class="synStatement">test</span> 数値をファイルへ書き込む, expects<span class="synComment"> #t ==&#62; ok</span>
<span class="synStatement">test</span> 数値が正常に書きこまれていることを確認する, expects <span class="synConstant">1234567890</span> <span class="synStatement">==&#62;</span> ok
<span class="synStatement">test</span> 文字列をファイルへ書き込む, expects<span class="synComment"> #t ==&#62; ok</span>
<span class="synStatement">test</span> 文字列が正常に書きこまれていることを確認する, expects <span class="synConstant">1234567890</span> <span class="synStatement">==&#62;</span> ok
<span class="synStatement">&#60;</span>異常系<span class="synStatement">&#62;</span>--------------------------------------------------------------------------
<span class="synStatement">test</span> ファイルが存在しない場合は読み込み処理は<span class="synComment"> #f を返す, expects #f ==&#62; ok</span>
<span class="synStatement">test</span> エポックタイム形式以外のデータを書き込む, expects<span class="synComment"> #t ==&#62; ok</span>
<span class="synStatement">test</span> エポックタイム形式以外のデータを読み込んだ場合は<span class="synComment"> #f を返す, expects #f ==&#62; ok</span>
<span class="synStatement">test</span> ファイルが存在しない場合は、書き込み処理はファイル作成して<span class="synComment"> #t を返す, expects #t ==&#62; ok</span>
<span class="synStatement">test</span> 正常に書きこまれていることを確認する, expects <span class="synConstant">1234567890</span> <span class="synStatement">==&#62;</span> ok
<span class="synStatement">&#60;</span>現状復帰<span class="synStatement">&#62;</span>-------------------------------------------------------------------------
<span class="synStatement">test</span> データファイルの回復, expects<span class="synComment"> #t ==&#62; ok</span>
passed.
</pre>
</div>