ファイル出入力

設定ファイルを読み込みパラメータをセッティングするために、ファイルの出入力部分を作ってみた。

ファイルオープン

とりあえず、テスト用 inputFile.dat は以下のような形式だと仮定。

001 North 0x0a
002 South 0x0b
003 East  0x0c
(以下同様).. .. ..

まずは、ファイルオープン。

import std.cstream;
import std.stream;
import std.c.stdio;
import std.string;

int main(char[][] args)
{
  char [] input = "inputFile.dat";
  File fp = new File(input,FileMode.In);

  // process..

  fp.close();
  return 0;
}

引数使えよ。って突っ込みはなしで^^;

読み込み実装1

実際に読み込む部分の実装方法1。foreachを使って読み込んでみる。ファイルの最初から最後まで同じ形式のファイルならばいけるけれど、普通はそんなことないから、実用的ではないかも。

  int i = 0;
  int [] number1,number2;
  char *c_type;
  char [][] direction;
  char [] tmp;
  c_type = toStringz(tmp);
  foreach(char [] line; fp){
    number1.length = number1.length + 1;
    number2.length = number2.length + 1;
    direction.length = direction.length + 1;
    sscanf(toStringz(line),"%d %s 0x%x",&number1[i],c_type,&number2[i]);
    direction[i] = toString(c_type).dup;
    i++;
  }

なぜ、number1.lenght += 1 が使えないのだろう。。。C言語のsscanfと同じような機能をもったD言語の関数を見つけられなかったのでC言語のsscanfを利用。文字列の扱いがC言語D言語で違うためtoString()とtoStringz()を用いてCとDの文字列のやり取りをしている。あと、基本的にD言語の配列のコピーを使いたいときは、.dupをつけないと参照先が同じため一箇所変更を加えると全部変わってしまうので注意。

読み込み実装2

行ごとに読み込むのではなく、1単語ごとに読み込んで処理する。フラグなど立てておけば分岐が出来るのでこっちのほうが色々できそう。

  int i = 0;
  int [] number1,number2;
  char *c_type;
  char [][] direction;
  char [] tmp;
  char [] line;
  c_type = toStringz(tmp);
  
  int mode = 0;
  while(1){
    fp.readf("%s",&line);
    if(fp.eof()) break;
    switch(mode){
    case 0:
      number1.length = number1.length+1;
      sscanf(toStringz(line),"%d",&number1[i]);
      mode++;
      break;
    case 1:
      direction.length = direction.length + 1;
      sscanf(toStringz(line),"%s",c_type);
      direction[i] = toString(c_type).dup;
      mode++;
      break;
    case 2:
      number2.length = number2.length+1;
      sscanf(toStringz(line),"0x%x",&number2[i]);
      mode = 0;
      i++;
      break;
    }
  }

それにしても、もっと上手にやる方法を考えなくては^^;まだ全然わからん^^;