第8話 INIファイル

--------------------- 第8話 INIファイル --------------------------


はじまり、はじまり~。


<INIファイルって何だっけ?>
イニシャルファイル。 初期設定ファイルのことさ。
詳しくは http://ja.wikipedia.org/wiki/INI%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB を参照。

<で、言いたいことは?>
INIファイルにすると便利だよ。

<それだけかい!>
INIファイルにすると簡単だよ。

<ワカッタ。もういい。>
では、おしまい。

 

----------------------------------------------------------------------
提供は~ 

 

<・・・いや、ココで終わるのはマズイでしょ。>
そう?

<せめてコメント入れようよ。>
INIファイル関連の関数は前振りなしでイキナリ使えるので、とっても便利。
テキストファイルの初期設定なら、まず最初に考えたいね。

<どうして?>
多くの場合データ形式が決まっているが、自由に設定できる場合はまず最初に検討しよう。
ファイルを作成するのを嫌う人もいるが、広く一般に使われている上に便利だ。

また使い方によっては、ブロックとして書き込めるので、さらに便利!ダメならAPIを呼んで使える。
いずれにせよ、使える機能ではあるね。

<普通にファイル処理するに比べてどんな利点があるの?>
既に述べたようにブロック化、扱いが簡単、使い方によっては大幅な高速化など。

<高速化? どのくらい?>
100倍以上もありうる。

<またまた口からデマカセを>
下記参照。

<あら、まあ質問者自身が認めている。しかも142倍!! ・・・熱が出て来たわ。>

 

----------------------------------------------------------------------

提供は: 人生を初期化(INI)したい。 Linersでした。

----------------------------------------------------------------------


uwsc.ini の書き換え mm 【2007/05/25 22:50:59】 [返信] [削除]

//下記のスクリプトを実行すると、uwsc.ini を書き換えているのですが、
//実際には読み込まれていません。標準のコマンドではダメなのでしょうか?


//////////////////////////////////////////////////


// uwsc.ini を書き換える

// uwsc.exe 配下のフォルダ10個、その中の各 uwsファイル10個 を、ランチメニュに登録する
// フォルダ名を、階層名にする


// uwsc.exe uws folder1 file1.uws
//              file2.uws
//              file3.uws
//                -
//                -
//                -
//              file10.uws

//         folder2
//         folder3
//          -
//          -
//          -
//         folder10


//////////////////////////////////////////////////


for i=1 to 10
  階層名=betweenstr(","+chgmoj(trim(doscmd("dir /b "+get_uwsc_dir+"uws")),"<#cr>",",,")+",",",",",",i)
  deleteini("lunchmenu","T"+i,get_uwsc_dir+"uwsc.ini")
  deleteini("lunchmenu","S"+i,get_uwsc_dir+"uwsc.ini")
  writeini("lunchmenu","T"+i,階層名,get_uwsc_dir+"uwsc.ini")
  readini("lunchmenu","T"+i,get_uwsc_dir+"uwsc.ini")
  
  for j=1 to 10
    値=betweenstr(","+chgmoj(trim(doscmd("dir /b "+get_uwsc_dir+"uws"+階層名+"*.uws")),"<#cr>",",,")+",",",",",",j)
    deleteini("lunchmenu","T"+i+"-C"+j,get_uwsc_dir+"uwsc.ini")
    writeini("lunchmenu","T"+i+"-C"+j,値,get_uwsc_dir+"uwsc.ini")
    readini("lunchmenu","T"+i+"-C"+j,get_uwsc_dir+"uwsc.ini")
    
    値=betweenstr(","+chgmoj(trim(doscmd("dir /s /b "+get_uwsc_dir+"uws"+階層名+"*.uws")),"<#cr>",",,")+",",",",",",j)
    deleteini("lunchmenu","S"+i+"-C"+j,get_uwsc_dir+"uwsc.ini")
    writeini("lunchmenu","S"+i+"-C"+j,値,get_uwsc_dir+"uwsc.ini")
    readini("lunchmenu","S"+i+"-C"+j,get_uwsc_dir+"uwsc.ini")
    sleep(0.01)
  next
  sleep(0.01)
next


Re:uwsc.ini の書き換え mm 【2007/05/26 12:11:31】 [削除]

//また少し書き直しました。


for i=1 to 10
  階層名=betweenstr(","+chgmoj(trim(doscmd("dir /ad /b "+get_uwsc_dir+"uws")),"<#cr>",",,")+",",",",",",i) // /ad を付加
  deleteini("lunchmenu","T"+i,get_uwsc_dir+"uwsc.ini")
  deleteini("lunchmenu","S"+i,get_uwsc_dir+"uwsc.ini")
  writeini("lunchmenu","T"+i,階層名,get_uwsc_dir+"uwsc.ini")
  
  for j=1 to 10
    値=betweenstr(","+chgmoj(trim(doscmd("dir /b "+get_uwsc_dir+"uws"+階層名+"*.uws")),"<#cr>",",,")+",",",",",",j)
    deleteini("lunchmenu","T"+i+"-C"+j,get_uwsc_dir+"uwsc.ini")
    writeini("lunchmenu","T"+i+"-C"+j,値,get_uwsc_dir+"uwsc.ini")
    
    値=betweenstr(","+chgmoj(trim(doscmd("dir /b "+get_uwsc_dir+"uws"+階層名+"*.uws")),"<#cr>",",,")+",",",",",",j) // /s を削除
    deleteini("lunchmenu","S"+i+"-C"+j,get_uwsc_dir+"uwsc.ini")
    writeini("lunchmenu","S"+i+"-C"+j,".uws"+階層名+""+ 値,get_uwsc_dir+"uwsc.ini") // 相対パスにする
    sleep(0.01)
  next
  sleep(0.01)
next


Re:uwsc.ini の書き換え Liners 【2007/05/26 16:46:24】 [削除]

設定できているようで良かったですね。書き込みだけですからreadiniはいらないですし、不具合がなければdeleteiniも必要ないでしょう。
それにしてもコノbetweenstrの使い方は・・・自分のスクリプトを見ているようでした。


Re:uwsc.ini の書き換え mm 【2007/05/26 19:22:54】 [削除]

返信ありがとうございます。

deleteini を省略すると、上書きにならず、追加書き込みにっていた原因が分かりました。
階層化せずに登録していたスクリプトファイルが生きているのです。
同じ形式で階層化して、100ファイル登録するようにすれば、問題はないような気がします。

一度ランチメニュを呼び出ないと、読み込まれた状態にならないということは、
スクリプトファイルからは uwsc.ini を書き換えるようには iniファイルコマンドは
作られていないということでしょうか?

手作業で uwsc.ini ファイルを編集しても、その後、ランチメニュを呼び出し、閉じると、
設定が反映されます。


Re:uwsc.ini の書き換え mm 【2007/05/26 19:29:45】 [削除]

続く。

そうであれば、iniコマンドを使わないで、テキスト編集するスクリプトを作成実行すればいいのかも。
まだ実験はしていませんが、書き換えスピードがはやくなるかも。


Re:uwsc.ini の書き換え mm 【2007/05/26 19:42:02】 [削除]

しっこく続く。

betweenstr は仕組みが分かりやすくて大好きになりました。
はさんで取り出し、しかも順番指定もでき、後ろからでも。

25:ランダム関数の事で「回り道」(一行野郎復活?)
http://iriyak.adam.ne.jp/wiliki/uwsc.cgi?Liners%bd%d0%c4%a5%bd%ea
に感謝いたします。


Re:uwsc.ini の書き換え Liners 【2007/05/26 21:11:58】 [削除]

>スクリプトファイルからは uwsc.ini を書き換えるようには iniファイルコマンドは作られていないということでしょうか?
詳細はumiumi様でないと何とも言えませんが、通常ini(初期設定ファイル)は起動時に読込まれ、終了時に新たな設定に書き換えられます。

よって書換えた後、ランチメニュを呼び出して初めて設定が有効になると考えられます。
また、スピードアップに関しては、色々考えられます。直接iniを編集するものその一つですが、セクションの切り分けに手間取るでしょう。

iniファイルの編集ではありませんが、私が良く使う手法に「ブロックごと書換える」があります。最初にセクションごと消し、最後の一回で
セクションごと書き込むのです。

ちょうどbetweenstr+chgmojとは逆に文字列に"<#cr>"を追加しながら溜めて行き最後に出力します。おそらく速度低下の原因はiniファイル
コマンドにあると思われるので、その回数を減らすことで改善できるのではないでしょうか?


Re:uwsc.ini の書き換え mm 【2007/05/26 22:53:47】 [削除]

// [SET]
//  ↓
// [SCHEDULE]
//  ↓
// [LUNCHMENU]

// の順で、uwsc.ini が構成されていると仮定して、以下のスクリプトを実行すると、
// 書き換えが8秒くらいになりました。ありがとうございました。


str="[SET]"+betweenstr(doscmd("type "+get_uwsc_dir+"uwsc.ini"),"[SET]","[LUNCHMENU]")


lunch="[LUNCHMENU]<#cr>Position=1,0<#cr>"
for i=1 to 10
  階層名=betweenstr(","+chgmoj(trim(doscmd("dir /ad /b "+get_uwsc_dir+"uws")),"<#cr>",",,")+",",",",",",i)
  lunch=lunch+"T"+i+"="+階層名+"<#cr>"

  for j=1 to 10
    値=betweenstr(","+chgmoj(trim(doscmd("dir /b "+get_uwsc_dir+"uws"+階層名+"*.uws")),"<#cr>",",,")+",",",",",",j)
    lunch=lunch+"T"+i+"-C"+j+"="+値+"<#cr>"
    lunch=lunch+"S"+i+"-C"+j+"="+".uws"+階層名+""+値+"<#cr>"
  next
next


id=fopen(get_uwsc_dir+"uwsc.ini",f_write)
  fput(id,str+lunch)
fclose(id)


Re:uwsc.ini の書き換え Liners 【2007/05/26 23:38:54】 [削除]

良かったですね。それでは、オマケでさらに高速化のヒントを差し上げます。
その後の調査でiniコマンドより、値 = betweenstr~の方がむしろ時間がかかるのが判明しました。

コンパイラでも使われる最適化の一つに不変値のループからの追い出しがあります。効果的と思われるは下記ですが、いかがでしょうか?

  :
  str = ","+chgmoj(trim(doscmd("dir /b "+get_uwsc_dir+"uws"+階層名+"*.uws")),"<#cr>",",,") + ","
  for j=1 to 10
    値 = betweenstr(str, ",", ",", j)
:


Re:uwsc.ini の書き換え mm 【2007/05/27 14:26:44】 [削除]

// すごい! 1秒くらいでした。口で数えています。(^^;


// >不変値のループからの追い出し

// よくよく考えてみると、ドスコマンドは外部のコマンドになるので、
// 100回ループすると時間がかかるわけですね。
// findstr等 の検索の速さから、doscmd の時間負担を考えたことがありませんでした。
// よい考えをいただきました。ありがとうございました。

 

set="[SET]"+betweenstr(doscmd("type "+get_uwsc_dir+"uwsc.ini"),"[SET]","[LUNCHMENU]")


lunch="[LUNCHMENU]<#cr>Position=1,0<#cr>"
str=","+chgmoj(trim(doscmd("dir /ad /b "+get_uwsc_dir+"uws")),"<#cr>",",,")+","
for i=1 to 10
  階層名=betweenstr(str,",",",",i)
  lunch=lunch+"T"+i+"="+階層名+"<#cr>"


  str2=","+chgmoj(trim(doscmd("dir /b "+get_uwsc_dir+"uws"+階層名+"*.uws")),"<#cr>",",,")+","
  for j=1 to 10
    値=betweenstr(str2,",",",",j)
    lunch=lunch+"T"+i+"-C"+j+"="+値+"<#cr>"
    lunch=lunch+"S"+i+"-C"+j+"="+".uws"+階層名+""+値+"<#cr>"
  next
next


id=fopen(get_uwsc_dir+"uwsc.ini",f_write)
  fput(id,set+lunch)
fclose(id)


Re:uwsc.ini の書き換え mm 【2007/05/28 19:23:58】 [削除]

4つのスクリプトで、実行時間を調べてみました。

1. 「最初の投稿」版           → 22282ms(約22秒)
2. 「ブロックごと書換え」版       → 10750ms(約10秒)
3. 「不変値のループからの追い出し」版  → 1281ms(約1秒)
2. 「超高速」版             → 156ms(約0.1秒)
   http://iriyak.adam.ne.jp/wiliki/uwsc.cgi?Liners%bd%d0%c4%a5%bd%ea

結果は、約142倍速!!

う~~、考え込んでしまいそう...
ありがとうございました。

----------------------------------------------------------------------
----------------------------------------------------------------------

Liners掲示板にてiniファイルの操作質問があった。http://hidebbs.net/bbs/liners?n=40118276&s=7&m=10
最終的に目的が達成され、20秒かかっていたものが約1秒と20倍ものまさに桁違いの高速化が出来たようです。

本当に良かったですね。iniファイルの操作に関しては以前COM(API)版で試し、新バージョンで再検証するつもりでした。
下記がその質問と一秒になった最終版のスクリプトです。ここでは、さらに高速化について突っ込んで見ましょう。

///////////////////////////////////////////////////////////////////////////////

uwsc.ini の書き換え mm 【2007/05/25 22:50:59】 [返信] [削除]
//下記のスクリプトを実行すると、uwsc.ini を書き換えているのですが、
//実際には読み込まれていません。標準のコマンドではダメなのでしょうか?
// uwsc.ini を書き換える
// uwsc.exe 配下のフォルダ10個、その中の各 uwsファイル10個 を、ランチメニュに登録する
// フォルダ名を、階層名にする
// uwsc.exe uws folder1 file1.uws
//              file2.uws
//              file3.uws
//                :
//              file10.uws
//         folder2
//         folder3
//          :
//         folder10

///////////////////////////////////////////////////////////////////////////////

Re:uwsc.ini の書き換え mm 【2007/05/27 14:26:44】 [削除]
// すごい! 1秒くらいでした。口で数えています。(^^;
// >不変値のループからの追い出し
// よくよく考えてみると、ドスコマンドは外部のコマンドになるので、
// 100回ループすると時間がかかるわけですね。
// findstr等 の検索の速さから、doscmd の時間負担を考えたことがありませんでした。
// よい考えをいただきました。ありがとうございました。

set="[SET]"+betweenstr(doscmd("type "+get_uwsc_dir+"uwsc.ini"),"[SET]","[LUNCHMENU]")

lunch="[LUNCHMENU]<#cr>Position=1,0<#cr>"
str=","+chgmoj(trim(doscmd("dir /ad /b "+get_uwsc_dir+"uws")),"<#cr>",",,")+","
for i=1 to 10
  階層名=betweenstr(str,",",",",i)
  lunch=lunch+"T"+i+"="+階層名+"<#cr>"

  str2=","+chgmoj(trim(doscmd("dir /b "+get_uwsc_dir+"uws"+階層名+"*.uws")),"<#cr>",",,")+","
  for j=1 to 10
    値=betweenstr(str2,",",",",j)
    lunch=lunch+"T"+i+"-C"+j+"="+値+"<#cr>"
    lunch=lunch+"S"+i+"-C"+j+"="+".uws"+階層名+""+値+"<#cr>"
  next
next

id=fopen(get_uwsc_dir+"uwsc.ini",f_write)
  fput(id,set+lunch)
fclose(id)

///////////////////////////////////////////////////////////////////////////////

さて、ここからが本題。すでに20倍速になっているのに、さらに高速化の余地などあるのでしょうか?
まず先の20倍速化で外部コマンドの呼び出しが遅いのは分かっているので、doscmdの代わりにgetdirを使います。

また少し未練も残りますがbetweenstrも廃止して、文字列の切り出しもやめます。
トドメに、新バージョンでは実装されなかったセクション単位の書き込みをAPIで実装してみます。

これにより、ターゲットセクションのみ書換えが出来、余分な切出しや書込みをしなくて済みます。
大幅な変更ですが、やってることはコマンドの内製化と更なるループ外への追い出しです。

これらにより、さらに4~5倍ほどの高速化が期待できます。実行するとほとんど瞬時に完了します。
最初の時に比べると約100倍もの速度で、超高速と言っていいでしょう。

これほどの速さの違いを体験できるケースは、それほど多くありません。
それでは、ミリ秒の世界を是非体験してみてください。


t=gettime()*1000+G_TIME_ZZ

def_dll WritePrivateProfileSectionA(string, string, string):long;Kernel32.dll
s = "Position=1,0<#cr>"

for i=1 to 10
  getdir(get_uwsc_dir + "uws","")
  階層名 = GETDIR_FILES[i-1]
  s = s + "T" + i + "=" + 階層名 + "<#cr>"
  getdir(get_uwsc_dir + "uws"+階層名, "*.uws")

  for j=1 to 10
    s=s+"T"+i+"-C"+j+"="+GETDIR_FILES[j-1]+"<#cr>"+"S"+i+"-C"+j+"=.uws"+階層名+""+GETDIR_FILES[j-1]+"<#cr>"
  next
next

WritePrivateProfileSectionA("lunchmenu", s, get_uwsc_dir+"uwsc.ini")

msgbox(gettime()*1000-t+G_TIME_ZZ+"ミリ秒")

///////////////////////////////////////////////////////////////////////////////