外部仕様の検討とファイルアクセス関連処理
宮坂電人
2008/4/16
■テキスト変換ツールの汎用的な外部仕様
テキスト変換ツールの基本的な構想を示します。
手始めにテキスト変換ツールの外部仕様、つまりツールを使う側から見た仕様を考えてみましょう。コンソールからテキスト変換ツールtextConvToolを起動するとき、たいていは、
textConvTool -p パラメータ指定 ファイル指定
あるいは、
textConvTool -p パラメータ指定<標準入力指定> 標準出力指定
で「入力」「出力」「パラメータ」を指定します。
ツール側で指定されたものを解析するのは手間なので、「Model-View-Controler」の考えで処理を分離します。
・View:「入力」「出力」「パラメータ」などの指定の取り出しと結果の表示
・Model:処理に専念
といった感じになるでしょう。
本連載は、ソフトバンククリエイティブ刊行の『C MAGAZINE』に掲載された記事を、同社の許可を得てより抜きして転載するものです。 なお、 Webでの連載として転載するに当たり、若干表現を変更している点があります(例えば「本書は」としている部分は「本連載は」としていることや図版などの省略など)。その点ご了承ください。 |
■Model側の外部仕様
View側は「コンソールでツールを実現する場合」と「GUIでツールを実現する場合」で大幅に内容が変化しそうなので、View側はあと回しにします。あまり見かけに左右されないModel側から仕様を固めていくことで作業がしやすくなると思われます。
ツールのModel側(これ以降、ToolModelと呼ぶ)は処理に専念するといっても、必要な情報を外部から取り入れねばなりません。まずは、これをどう取り入れるかを決めましょう。
パラメータとして取り込むか、あるいは何らかの呼び出し機構を用意して、それを呼び出すかは別にして、Table 1に示すようなメソッドが必要だと思われます。
Table 1 ToolModelのインターフェイス | |
メソッド | 説明 |
void setOutput(byte[] iBytes); | iBytesの内容を標準出力に送る |
void setOutput(byte[] iBytes, int iOffset, int iSize); | iBytesの内容のうちiOffsetから始まる位置よりiSizeバイトぶんを標準出力に送る |
byte[] getInput(); | 標準入力の内容を取り出す |
Object getParam(Object iKey); | iKeyで示すパラメータを取得する |
java.util.Set getParamSet(); | パラメータの一覧を取得する |
String[] getFilenames(); | ファイル名の一覧を取得する |
textConvTool -p パラメータ指定 ファイル指定
で起動した状況では、getInput()を呼ぶと空っぽのbyte配列が戻り、getParam(”-p”)を呼ぶと“パラメータ指定”が戻り、getFilenames()を呼ぶとファイル指定が配列で戻る(複数のファイル指定がありうるので)というのを想像するとよいでしょう。また、
textConvTool -p パラメータ指定<標準入力指定> 標準出力指定
で起動した状況では、getInput()を呼ぶと標準入力から取り込んだ内容のbyte配列が戻り、setOutput()で標準出力に内容を書き込むことになるでしょう。
■支援サブルーチンの外部仕様
ToolModelで頻繁に使用すると考えられる処理を楽にするために、いくつかサブルーチンを用意しましょう。個々の処理を誰が処理するのかはあとで検討するとして、まずは必要になりそうな処理をTable 2にあげてみましょう。
Table 2 支援サブルーチンの外部仕様 | |
メソッド | 説明 |
static byte[] fileToBytes(String iFilename); | iFilenameで指定のファイルの内容をbyte配列にして返す |
static void bytesToFile(byte[] iBytes, int iOffset, int iSize, String iFilename); |
iBytesの内容のうちiOffsetから始まる位置よりiSizeバイト分をiFilenameで指定のファイルとして書き出す |
byte配列から1行を取り出すオブジェクト | 本文のOneLinePickerの解説を参照 |
byte配列を構築するオブジェクト | 本文のBytesBuilderの解説を参照 |
byteの特性を判断するサブルーチンとbyte配列の操作をするサブルーチン | 本文のBytesMiscの解説を参照 |
Table 2に示したもののうち、fileToBytesとbytesToFileは標準入力や標準出力が指定されていなかったときに重宝するでしょう。通常はbyte配列の読み書きで処理を記述しておき、ファイル指定があったときにfileToBytes()とbytesToFile()を使うことで簡単にファイル対応ができるはずです。
■OneLinePicker
byte配列から1行を取り出すオブジェクトのクラスです。テキスト変換では1行ずつ取り出して処理をしたい状況がありがちです。やっかいなのはOSによって改行コードが違うことがあり、これをおのおののToolModelで判断させるのは、わずらわしいだけでなくバグを誘発しやすくなります。というわけで、1行ずつ取り出す処理をクラスにします。Table 3のようなメソッドが必要になるでしょう。
取り扱う改行コードに関しては今のところ以下の3パターンのみとします。
CR+LF(0Dh、0Ah)……主にMS-DOS、Windowsでよく使われる
CRのみ(0Dh)……主に旧MacOSでよく使われる
LFのみ(0Ah)……主にUNIX系OSでよく使われる
Table 3 OneLinePickerのメソッド | |
メソッド | 説明 |
OneLinePicker(byte[] iBytes); | コンストラクタ。iBytesを処理対象とする |
OneLinePicker(byte[] iBytes, int iOffset, int iSize); |
iBytesの内容のうちiOffsetから始まる位置よりiSizeバイトぶんを処理対象とするためのコンストラクタ |
boolean pick(); | 1行ぶんを取り出す。取り出せたならtrueを返し、そうでないならfalseを返す |
byte[] getBytes(); | 取り出したbyte配列を返す |
int getBegin(); | 取り出した1行ぶんの開始位置を返す |
int getSize(); | 取り出した1行ぶんのサイズを返す |
■BytesBuilder
byte配列を構築するオブジェクトのクラスです。出力したいデータが元のbyte配列より大きくなることはよくあります。そこで、このクラスで作られたオブジェクトに対して出力することで、あらかじめどれだけの大きさの配列を用意するか意識しなくてよいようにします。これにはTable 4に示すようなメソッドが必要でしょう。
Table 4 BytesBuilderのメソッド | |
メソッド | 説明 |
void add(byte iByte); | iByteを追加する |
void add(byte[] iBytes); | iBytesを追加する |
void add(byte[] iBytes, int iOffset, int iSize); |
iBytesの内容のうちiOffsetから始まる位置よりiSizeバイトぶんを追加する |
byte[] getAll(); | 追加された全内容を返す |
■BytesMisc
byteの特性を判断するサブルーチンやbyte配列の操作をするサブルーチンなどをまとめたクラスです。C言語の標準ライブラリにあるctype.hやstring.hに存在する標準関数のうち、charデータの判断、変換、コピーに使う関数のようなメソッドを用意します。今思いつくかぎりでもTable 5に示すようなメソッドが必要になるでしょう。Table 5に示したもの以外にも必要なサブルーチン的メソッドやクラスがあるかもしれませんが、とりあえずはこの範囲で次の検討作業に入ります。
Table 5 BytesMiscのメソッド | |
メソッド | 説明 |
static boolean isalnum(byte iB); | iBがアルファベットまたは数字ならtrueを返す |
static boolean isalpha(byte iB); | iBがアルファベットならtrueを返す |
static boolean iscntrl(byte iB); | iBが制御文字ならtrueを返す |
static boolean isdigit(byte iB); | iBが数字ならtrueを返す |
static boolean islower(byte iB); | iBが英小文字ならtrueを返す |
static boolean isupper(byte iB); | iBが英大文字ならtrueを返す |
static boolean isxdigit(byte iB); | iBが16進数文字ならtrueを返す |
static boolean isCRLF(byte iB); | iBが改行コードならtrueを返す |
static boolean isSJISZen1st(byte iB); | iBがShift JISの全角の1バイト目ならtrueを返す |
static int memchr(byte[] iBA, int iBegin, int iSize, byte iPat); |
iBAの内容のうちiBeginからiSizeバイトぶんの範囲で最初に見つかるiPatの位置を返す。見つからない場合は-1を返す |
static int memcmp(byte[] iBA, int iBegA, byte[] iBB, int iBegB, int iSize); |
iBAのiBegAから始まる部分とiBBのiBegBから始まる部分をiSizeぶん比較する。すべて一致すれば0を返し、一致しない場合はiBA側がiBB側より小さいならマイナス値を返し、そうでないならプラス値を返す |
static void memmove(byte[] iDest, int iBegD, byte[] iSrc, int iBegS, int iSize); |
iSrcのiBegSからiSizeぶんをiDestのiBegDから始まる部分 へコピーする |
static void memset(byte[] iDest, int iBegD, byte iPat, int iSize); |
iDestのiBegDからiSizeぶんの領域をiPatで埋める |
ほかに検討すべき項目 |
@IT自分戦略研究所は2014年2月、@ITのフォーラムになりました。
現在ご覧いただいている記事は、既掲載記事をアーカイブ化したものです。新着記事は、 新しくなったトップページよりご覧ください。
これからも、@IT自分戦略研究所をよろしくお願いいたします。