バイト配列からIntデータ取得方法

解決


GORI  2011-10-11 14:15:47  No: 103064  IP: [192.*.*.*]

お世話になります。VB6でやっています。
50000個のIntegerが入ったバイナリファイルを多数読み込んで処理する時間を短縮したく質問させていただきました。

従来はGet #nf, p, iVで場所を指定して順次読み込みをしていますが読み込みだけでかなり時間がかかってしまいます。そこで下記のようにバイト配列に一挙に読み込んで試した結果読み込み時間は極端に短縮されましたが配列からIntを取り出すところで時間が掛かってしまい、結果的に順次読み込みよりも長くなってしまいました。文字列(HEX)にしてからIntにするという無駄が原因かと思います。よい方法があったらお願いします。

Open kfile For Binary As #nf:Get #nf, , B: Close #nf

for i=1 to 50000
     p=(i-1)*2:d = "&H" & Hex(B(p + 1)) & Hex(B(p)):iV(i) = val(d)
next i

編集 削除
魔界の仮面弁士  2011-10-12 09:38:48  No: 103065  IP: [192.*.*.*]

> Get #nf, p, iVで場所を指定して順次読み込みをしていますが
ファイルのレイアウトによっては、Integer または Integer 配列を
メンバーにもつユーザー定義型(あるいはユーザー定義型配列)
読み込むことで、処理速度を向上させられるかもしれません。


> for i=1 to 50000
>      p=(i-1)*2:d = "&H" & Hex(B(p + 1)) & Hex(B(p)):iV(i) = val(d)
> next i
iV(0) は未使用なのですか?

たとえば、B(p + 1) と B(p) が &H0 と &H56 だった場合、結果は 86 (=&H56) です。
それでは、B(p + 1) と B(p) が &H5 と &H6 だった場合はどうでしょう。
本来は 1286 (=&H506) となるべき値が、上記では 86 (=&H56) になってしまいます。


もしも 1286 としたいなら、『iV(i) = B(p + 1) * &H100 + B(p)』の方が良いでしょう。
これならば、Hex による文字列変換も Val による Double 変換も発生しません。

編集 削除
GORI  2011-10-12 13:57:11  No: 103066  IP: [192.*.*.*]

魔界の仮面弁士様  ご回答をありがとうございました。

具体的に書かせていただきますと  B(0)=232 (&HE8)  B(1)=224 (&HE0) です。  求める数値は-7960です。最初は私も  Dim iV  as Integer  とし
iV = B(0) + B(1) * Clng(&H100) としてみましたが  232 + 224 * 256 = 57576  となってオーバーフローエラーがでてしまいましたのでHEXを使って文字データに変換してしてみたものです。文字列にしないで計算だけで-7960が得られれば速度もかなり早くなるかもしれませんので数値計算だけで処理する方法があればご教示いただきたく、お願いします。
PS  前回  d = "&H" & Hex(B(p + 1)) & Hex(B(p))と書きましたが"0"を加えて二桁にして処理すべきことに気づきました。

編集 削除
魔界の仮面弁士  2011-10-12 15:39:19  No: 103067  IP: [192.*.*.*]

> Clng(&H100) 
これは「&H100&」と書けますよ。


> 57576  となってオーバーフローエラーがでてしまいましたので
結果は Long で受けてください。
そうすれば 32768〜65535 以上の値も受けられます。


それらを Integer 型の負数部分におさめたいなら、
  If longValue >= &H8000& Then
    intValue = CInt(longValue - &H10000)
  Else
    intValue = CInt(longValue)
  End If
と記述できます。

編集 削除
Koz  2011-10-12 17:06:55  No: 103068  IP: [192.*.*.*]

これで良いような気がします。

Dim intArray() As Integer
Open "C:\TEMP\HOGE.dat" For Binary As #1
ReDim intArray(LOF(1) \ 2 - 1)
Get #1, , intArray
Close #1

編集 削除
魔界の仮面弁士  2011-10-12 17:19:21  No: 103069  IP: [192.*.*.*]

別案。
個人的にはあまり好きな方法ではないのですが、速度優先ということで。

'VB ランタイムの API
Private Declare Sub GetMem2 Lib "MSVBVM60" (ByVal ptr As Long, ByRef result As Integer)

  Dim intValue As Integer
  For i = 0 To 最大値 Step 2
    GetMem2 VarPtr(B(i)), intValue
    Debug.Print intValue
  Next

編集 削除
GORI  2011-10-13 12:16:18  No: 103070  IP: [192.*.*.*]

Koz様、魔界の仮面弁士様  各種の方式を試して見ましたが超高速読み込みが実現できました。ありがとうございます。  ここで各方式について読み取り+配列収納の処理速度を計ってみた結果を書きますと(約50KBを50ファイル)

1.場所を指定して順次読み込み  (Get #nf, p, iV(n))=7.023秒
2.バイナリ一括読み込みしてVal(HEX値)でInt値取得  =8.14秒
3.一括読み込みしてGetMem2 VarPtr(B(i)),iV(n)でInt値取得  =2.1093秒
4.IntArrayで一括して配列収納  =  0.046875秒

となって大成功でした。(結果数値確認しました)
こんなに高速でHDDから読めるとなると読み取ってから各種処理するよりも処理後のデータをHDDに入れておくほうがかなり早くなることが期待できます。
あらためてありがとうございました。

編集 削除