Win2000、VB.NETです。
固定長のテキストファイルの中から、
一致する文字列を見つけるというプログラムなんですが、
データが20000行近くあり、DO〜LOOPを使用すると、
対象の列が最初と最後の場合で、検索時間に
大きな幅ができてしまいます。
何か良い解決方法をご存知の方、ご教授願います!
検索してその後どうするかにもよるのですが、
ファイルから文字の検索となると、
DosのFindが速いのだが。。。
>ねろさん
アドバイスありがとうございます。
>検索してその後どうするかにもよるのですが、
テキストからデータを引っ張り出してきて、
VBで作成した画面上に項目毎に貼り付けていきます。
書き忘れですが、検索対象の部分が
昇順で並べられているので、二分法など
使えないでしょうか。。。
こんなプログラムでテストしてみました。
20万件の最後で一致するようにデータを作りました。
結果1秒もかからないですよ。
Dim a(200000) As String
Dim i As Long
For i = 1 To 200000
a(i) = "number" & Format(i)
Next
Debug.Print Now
For i = 1 To 200000
If a(i) = "number200000" Then
Debug.Print a(i)
Exit For
End If
Next
Debug.Print Now
PCのスペックはPentium4 2.53GHz メモリは512MB DDRです
>0123さん
ありがとうございます。
申し訳ないのですが、今回はファイルI/Oでして。。。
1行目と20,000行目では、
5秒くらいの差がついてしまうのです。
まだまだ書かれていない仕様がありそうですね。
他に条件があるのであれば先に書いておいたほうがいいですよ。
例えば文字列の部分一致を考慮するのか完全一致のみとするのか
データの書式が決まっているのかないのか等々...
後から小出しの条件は回答する側にとって2度手間になります。
こういうのはgrepとかfindstrなどのツールを使うほうがVBより速いかも。
Line Input # で1行づつ読んでるのなら...
メモリに余裕あるなら、GetとかFileSystemObjectのReadAllでメモリ上に展開してからモロモロの処理を行うとか、
とりあえず、何行目か決まっているのであれば、
テキストファイルの指定行を瞬時に読込む
http://www.bcap.co.jp/hanafusa/VBHLP/FSO13.htm
とか、
あと、PCのスペックにも激しく依存するので、
ターゲットになるマシンスペックと、目標タイム(何秒以内)とか
が具体的になれば、「燃え」られる人も出てくるかもしれない(^^;。
目標タイム(何秒以内)よりも、改善"率"が重要。
今30分かかっている処理で、
そのうち一部の処理で25分かかっています。その処理を20%改善して
20分に...とかさ
性能改善としてはそうゆう情報の方が俄然、燃える。
何%の改善を目標としているの?性能改善のために、
工数はどれほど割けるの?それによってアプローチの仕方も変わります。
たとえそれが10秒の短縮だとしても
1%の改善を行うのに2日も3日もそれだけに時間をかけてられないでしょ?
普通は?
#っとちょっと内容が真面目すぎて面白みが無かったかな?
ファイル上のデーターが固定長で、ソートされているのなら、FileStreamクラスの
Seekメソドと、BinaryReaderクラスのReadChars等を使って、二分木検索をすれば
いいのでは。
又は検索が複数回行われる場合は、最初に一旦全てのデーターを読み、検索にかかわる
頭の数文字分を配列データーに入れておいて、検索時は先ず配列から該当の文字
拾い出して、一致するデーターだけ配列のインデックスをKeyにファイルから読み込む
等の方式もありかな。
ファイルから文字列を検索する場合、ハードディスクや、ネットワークからデーターを
読み出す訳ですから、データーが何行有るというよりも、ファイル全体の大きさが、
処理時間に関しては支配的になります。
たとえば、
『80バイトの固定長データーがソートされて20,000行程度、ファイルに保存されています。
この中から複数回文字を検索するのですが、現在ファイルの頭から一行ずつ読み込んで
検索しているので、検索文字がファイルの最後の方に有ると5秒程度かかってしまいます。
これを革命的に短縮する方法を。。。。。』等と書けば判りやすいのでは。
更に、データーの形式は
ID=XXXXXXXXXX NAME=YYYYYYYYYY ...
X,Yは半角英数字、改行付き
などと書けば親切。
マシンスペックに関しては、データーが保存されているメディアの読み出し速度、
たとえばハードディスクに保存されているので有れば、ハードディスクのスペックが、
ネットワーク上のファイルであればであれば、ネットワークのスピードが処理速度に
関しては支配的になります。
ハードディスクはUltra ATA/100 、シークタイム8 ms avg
フォーマット方式ははNTFS...
等と書くのは少々行き過ぎ。。。
>>検索してその後どうするかにもよるのですが、
>テキストからデータを引っ張り出してきて、
>VBで作成した画面上に項目毎に貼り付けていきます。
例えば以下のようなことであればファイルを1回パスするだけでおこなえます。(ファイル内が昇順に並べ替え済みとして)
品番に対する価格を求めるような例
品番 価格(本当はこの時点では不明)
jj-123456 5.500
xx-123456 6.600
dd-123456 4.800
aa-123456 5.700
のようなものを求めたいと仮定すれば品番側をソートし
品番 価格(これを求める)
aa-123456 5.700
dd-123456 4.800
jj-123456 5.500
xx-123456 6.600
とすれば品番 aa-123456 が見つかった位置から次の品番 dd-123456 を検索
すればよいのでデータのファイルを1回パスするだけで済みます。
あくまで仮定の話ですが、使えるようなら他の高速化技法と合わせて検討してください。
>ご回答下さった皆さん
様々なご意見ありがとうございます。
『検索を速くする』だけでは曖昧すぎたんですね。。。
特に >さささん のご意見には、なるほど、と思いました。
今回の条件は、ほとんど >ねろさんの仰るとおりで、
>80バイトの固定長データーがソートされて20,000行程度、ファイルに保存されています。
>この中から複数回文字を検索するのですが、現在ファイルの頭から一行ずつ読み込んで
>検索しているので、検索文字がファイルの最後の方に有ると5秒程度かかってしまいます。
>これを革命的に短縮する方法を。。。。。
このうち、80バイトでなく150バイトで、後は一緒です。
>ねろさん のアドバイスを参考にさせて頂き、FileStreamクラスの
Seekメソドを使用した二分木検索を採用し、最大5秒掛かっていた処理を
3秒に短縮することができました。
アドバイス頂いた皆様、特に >ねろさん 、有難う御座いました。
解決チェック忘れました。。。
ランダムファイルを二分木検索で読み込む方法は
それはそれである程度のブレーク・スルーで有ると思いますが、
一行150Byteで20,000行程度ならせいぜい3Mbyteですね。
この程度のファイルであれば、一度に読み込んでON MEMORY
で処理した方が、速くて簡単だと思います。
私の環境の中で非力そうなコンピューターで試しても、全て配列に
読み込むのに0.8秒、Instrを使った最後の方の検索で、0.02秒です。
時間がかかっているのは、読み込みではなく、文字列の処理の方では
無いのでしょうか。
ツイート | ![]() |