C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

VBでCRC32を高速で計算する方法

[トピック内 95 記事 (1 - 20 表示)]  << 0 | 1 | 2 | 3 | 4 >>

■82326 / inTopicNo.1)  VBでCRC32を高速で計算する方法
  
□投稿者/ ぎゅんぎゅ (1回)-(2017/01/02(Mon) 20:51:06)

分類:[.NET 全般] 



VB.NETで、ファイルからCRC32ハッシュを高速で計算する方法を教えてください。

http://dotnet-snippets.com/snippet/calculate-crc32-hash-from-file/587

このページにあるコードを使うと
ハッシュを得ることができるのですが、
500MBのファイルのハッシュを計算するのに5秒くらいかかります。

一方で、WinRARを使って
同じ500MBのファイルを無圧縮zipファイルに変換すると
1〜2秒程度で生成することができ、CRCも得ることができます。

一体、どうすればこのように高速にCRCを得ることができるのでしょうか?


https://code.msdn.microsoft.com/office/VBACRC-32-dad7d087

このページには4KBずつ読み込めば8〜10倍程度速くなると書かれてあります。

VBA用に書かれたものなので
以下のようにVB.NET用に書き換えて使ってみたのですが
5倍くらい遅くなってしまいました。

WinRARではどういうアルゴリズムを使っているのでしょうか?


Public Function GetCRC32(ByVal sFileName As String) As String
Dim R&, I%, FN%, FL&
Dim Buf() As Byte
If Crc32Table(255) = 0 Then InitCrc32Table()



Using stream As Stream = File.OpenRead(sFileName)
Using reader As New BinaryReader(stream)
FL = stream.Length


'FL = LOF(FN)
R = Not 0
ReDim Buf(4095)
While FL > 0
If FL < 4096 Then ReDim Buf(FL - 1)
Buf = reader.ReadBytes(Buf.Length) 'Get #1, , buf()

'Get #FN, , Buf
For I = 0 To UBound(Buf)
R = (Int(R / 256) And &HFFFFFF) Xor Crc32Table((R Xor Buf(I)) And &HFF)
Next I
FL = FL - UBound(Buf) - 1
End While

End Using
End Using

GetCRC32 = Not R


End Function




http://dobon.net/vb/dotnet/string/filemd5.html

ちなみに、このページの方法を使ってMD5の計算も行ってみたのですが
CRC32と同じく5秒程度かかりました。


引用返信 編集キー/
■82327 / inTopicNo.2)  Re[1]: VBでCRC32を高速で計算する方法
□投稿者/ ぎゅんぎゅ (2回)-(2017/01/02(Mon) 21:14:03)
一つ思いましたが
VBで計算しているから遅いのでしょうか?
C++で計算すれば高速でしょうか?

C++で書かれたDLLがないか検索して調べてみましたが
なぜか見つかりませんでした。

どなたかご存じでしたら教えてください。
 
引用返信 編集キー/
■82328 / inTopicNo.3)  Re[2]: VBでCRC32を高速で計算する方法
□投稿者/ もりお (28回)-(2017/01/02(Mon) 22:18:49)
2017/01/02(Mon) 23:21:06 編集(投稿者)

No82327 (ぎゅんぎゅ さん) に返信
5秒かかっていたものが5倍遅くなるってことは25秒ですよね
言語の違いがあるとしても1~2秒のものが25秒かかるのはちょっと開きが大きいかなと

アルゴリズムの違いがあるのかもしれませんね
私はこれより速いアルゴリズムを知りませんけれども
なんかありそうな気はしますよね

VB.NETで処理が遅くなる原因としまして遅延バインディングがあります
数億回のループをぶんぶん回すようなときは無視できないくらい影響があります
Option StrictをOnにして型を書きまくって
それでもう一回試してみてはいかがでしょうか
うまくいけばWinRARに肉薄できるかもしれません
引用返信 編集キー/
■82329 / inTopicNo.4)  Re[1]: VBでCRC32を高速で計算する方法
□投稿者/ Azulean (758回)-(2017/01/03(Tue) 18:00:35)
No82326 (ぎゅんぎゅ さん) に返信
> このページには4KBずつ読み込めば8〜10倍程度速くなると書かれてあります。
>
> VBA用に書かれたものなので
> 以下のようにVB.NET用に書き換えて使ってみたのですが
> 5倍くらい遅くなってしまいました。

そもそも、最初のリンクの内容も 4KB ずつ処理する仕組みのようですので、同じようなことをやろうとして遅くなっているのかと。
元のコードは割り算を \ でやっているのに対して、VBA から移植したコードは / にしているので浮動小数演算に化けた結果、数倍遅くなっています。

引用返信 編集キー/
■82330 / inTopicNo.5)  Re[2]: VBでCRC32を高速で計算する方法
□投稿者/ Azulean (759回)-(2017/01/03(Tue) 18:10:59)
No82327 (ぎゅんぎゅ さん) に返信
> 一つ思いましたが
> VBで計算しているから遅いのでしょうか?
> C++で計算すれば高速でしょうか?

可能性はあります。
なお、C# で unsafe にして配列を fixed し、ポインターアクセスするように書き換えると、3 秒を切ってくるようです。
VB.NET にはポインターがなかった…はずなので、一定以上の速度改善は難しいように思えます。
引用返信 編集キー/
■82331 / inTopicNo.6)  Re[2]: VBでCRC32を高速で計算する方法
□投稿者/ Hongliang (481回)-(2017/01/04(Wed) 00:58:36)
最初のリンク先でのコードをベースに、何点か。具体的な数字は環境に依存するので特に記述しませんが。

・Debugモードで計測しているのであれば、Releaseモードで試してみてください。

・「対象のCPU」がx64かx86かで結構変わったりします。

・本来は符号無し整数として行うべき演算を、このコードでは符号付き整数で演算しています。
 IntegerをUIntegerに変更(リテラルの整数値は&HxxxxUIとしてUIntegerであることを明示)してみてください。
 (ループ変数i, jはIntegerのままで良いです)
 (Option Strict Onにしてエラー・警告が出ないように)

・UIntegerで演算を行えるなら、
> CRC32Result = ((CRC32Result And &HFFFFFF00) \ &H100) And &HFFFFFF
> CRC32Result = CRC32Result Xor CRC32Table(n)
という部分を、
CRC32Result = (CRC32Result >> 8) Xor CRC32Table(CInt(n))
に簡略化することができます。
引用返信 編集キー/
■82332 / inTopicNo.7)  Re[3]: VBでCRC32を高速で計算する方法
□投稿者/ ぎゅんぎゅ (3回)-(2017/01/04(Wed) 10:49:16)
ありがとうございます。

Uintegerにする方法ですが
これで良いでしょうか?


Public Function GetCRC32_2(ByVal sFileName As String) As String

Try
Dim FS As FileStream = New FileStream(sFileName, FileMode.Open, FileAccess.Read, FileShare.Read, 8192)
Dim CRC32Result As Integer = &HFFFFFFFF
Dim Buffer(4096) As Byte
Dim ReadSize As Integer = 4096
Dim Count As Integer = FS.Read(Buffer, 0, ReadSize)
Dim CRC32Table(256) As Integer
Dim DWPolynomial As Integer = &HEDB88320
Dim DWCRC As Integer
Dim i As Integer, j As Integer, n As Integer

'Create CRC32 Table
For i = 0 To 255
DWCRC = i
For j = 8 To 1 Step -1
If (DWCRC And 1) Then
DWCRC = ((DWCRC And &HFFFFFFFE) \ 2&) And &H7FFFFFFF
DWCRC = DWCRC Xor DWPolynomial
Else
DWCRC = ((DWCRC And &HFFFFFFFE) \ 2&) And &H7FFFFFFF
End If
Next j
CRC32Table(i) = DWCRC
Next i

'Calcualting CRC32 Hash
Do While (Count > 0)
For i = 0 To Count - 1
n = (CRC32Result And &HFF) Xor Buffer(i)
CRC32Result = (CRC32Result >> 8) Xor CRC32Table(CInt(n))
Next i
Count = FS.Read(Buffer, 0, ReadSize)
Loop
Return Hex(Not (CRC32Result))
Catch ex As Exception
Return ""
End Try

End Function



CRC32Result だけuintegerにしましたが、
計算結果が出力されません。
CRCTableもuintegerにしてみましたが、
CRCTableが出力されずに終了してしまいます。

どうすれば良いでしょうか?
 
引用返信 編集キー/
■82333 / inTopicNo.8)  Re[4]: VBでCRC32を高速で計算する方法
□投稿者/ ぎゅんぎゅ (4回)-(2017/01/04(Wed) 10:52:51)
すいません、勘違いでした

二倍程度速くなりました。

ありがとうございます。

他の設定も試してみます

引用返信 編集キー/
■82334 / inTopicNo.9)  Re[5]: VBでCRC32を高速で計算する方法
□投稿者/ ぎゅんぎゅ (6回)-(2017/01/04(Wed) 12:00:04)
いろいろと試してみたのですが
教えてくださった通り
uintegerにすることで2倍程度の高速化が実現できました。

Option Strict Onは面倒なので試していません。
これをするくらいならC#で書き直してDLLとして使用した方が良いのではないでしょうか?

この状態で
http://dobon.net/vb/dotnet/string/filemd5.html
のMD5の計算と速度比較を行いましたが
20〜30%程度CRC計算の方が遅いです。

http://d.hatena.ne.jp/shiku_otomiya/20111026/p1
このページによると
CRCの方が逆に20〜30%程度高速であるはずなので、
まだあと2倍程度高速化できる余地が残っていると思います。

「対象のCPU」に関してですが

https://social.msdn.microsoft.com/Forums/vstudio/ja-JP/ae468f23-f3e5-4e0c-b744-326190c739f3?forum=vbgeneralja

プロパティ>コンパイルタグ>コンパイラの詳細設定
を見てみましたが設定箇所が見当たりませんでした

VS2010のExpressを使っているためだと思います。

「vbproj」ファイルを直接弄れば設定ができると思うのですが
どこを変えれば良いですか?
ファイル内をCPUで検索してもかからなかったので教えてください



引用返信 編集キー/
■82335 / inTopicNo.10)  Re[6]: VBでCRC32を高速で計算する方法
□投稿者/ ぎゅんぎゅ (8回)-(2017/01/04(Wed) 12:08:29)
何度もすいません、うまくいったと思ったのですが
これも勘違いで宣言がintegerのままになっていました

これでうまくいかないのですが何が問題でしょうか?

Public Crc32Table2(255) As UInteger


Private Sub InitCrc32Table2()

Dim DWPolynomial As UInteger = &HEDB88320UI
Dim DWCRC As UInteger

'Create CRC32 Table
For i = 0 To 255
DWCRC = i
For j = 8 To 1 Step -1
If (DWCRC And 1) Then
DWCRC = ((DWCRC And &HFFFFFFFEUI) \ 2&) And &H7FFFFFFFUI
DWCRC = DWCRC Xor DWPolynomial
Else
DWCRC = ((DWCRC And &HFFFFFFFEUI) \ 2&) And &H7FFFFFFFUI
End If
Next j
Crc32Table2(i) = DWCRC
Next i


End Sub


Public Function GetCRC32_2(ByVal sFileName As String) As String


If Crc32Table2(255) = 0 Then InitCrc32Table()


Dim FS As FileStream = New FileStream(sFileName, FileMode.Open, FileAccess.Read, FileShare.Read, 8192)
Dim CRC32Result As UInteger = &HFFFFFFFFUI
Dim Buffer(4096) As Byte
Dim ReadSize As Integer = 4096
Dim Count As Integer = FS.Read(Buffer, 0, ReadSize)
Dim i As Integer, n As Integer


'Calcualting CRC32 Hash
Do While (Count > 0)
For i = 0 To Count - 1
n = (CRC32Result And &HFFUI) Xor Buffer(i)
CRC32Result = (CRC32Result >> 8) Xor Crc32Table2(CInt(n))
Next i
Count = FS.Read(Buffer, 0, ReadSize)
Loop
Return Hex(Not (CRC32Result))

End Function


引用返信 編集キー/
■82336 / inTopicNo.11)  Re[7]: VBでCRC32を高速で計算する方法
□投稿者/ ぎゅんぎゅ (9回)-(2017/01/04(Wed) 12:11:14)
何度も何度もすいません
If Crc32Table2(255) = 0 Then InitCrc32Table()

If Crc32Table2(255) = 0 Then InitCrc32Table2()

にすればうまくいきました。

あとは、CPUの設定の方法をお教え願えますでしょうか?

 
引用返信 編集キー/
■82337 / inTopicNo.12)  Re[6]: VBでCRC32を高速で計算する方法
□投稿者/ WebSurfer (1112回)-(2017/01/04(Wed) 12:38:21)
No82334 (ぎゅんぎゅ さん) に返信

> これをするくらいならC#で書き直してDLLとして使用した方が良いのではないでしょうか?

C# でもよければ以下の記事のものを試してみてはいかがですか? ソースはその記事から
リンクを貼ってある GitHub のページにあります。

Calculating CRC-32 in C# and .NET
https://damieng.com/blog/2006/08/08/calculating_crc32_in_c_and_net

質問者さんの作ったものより速いかどうかは分かりませんが・・・

引用返信 編集キー/
■82338 / inTopicNo.13)  Re[8]: VBでCRC32を高速で計算する方法
□投稿者/ WebSurfer (1113回)-(2017/01/04(Wed) 12:44:40)
No82336 (ぎゅんぎゅ さん) に返信

> あとは、CPUの設定の方法をお教え願えますでしょうか?

プラットフォームターゲットのことであれば、ソリューションエクスプローラー
で Properties を右クリックして開いて[ビルド]タブをクリックすれば出てき
ます。
引用返信 編集キー/
■82339 / inTopicNo.14)  Re[7]: VBでCRC32を高速で計算する方法
□投稿者/ Hongliang (482回)-(2017/01/04(Wed) 13:05:23)
> Option Strict Onは面倒なので試していません。
> これをするくらいならC#で書き直してDLLとして使用した方が良いのではないでしょうか?

プロジェクト全体としてOnにすべきとまでは言いませんが。
今回のように、できない、勘違いだった、やっぱりできてない、できた、というのを繰り返すぐらいなら、
該当部分だけ別ファイル(のモジュール等)に切り出して、そのファイルだけOption Strict Onにしたほうがかえって手間が少なくなるかと思います。

なお、ファイルから読み込んで全部のバイトを舐める、という作業自体の時間ってのが意外に掛かります。
CRCの計算時間がMD5の計算時間より30%短いといっても、ファイル読込を含んだ総時間は多分大差ない程度に収まるはずです。
引用返信 編集キー/
■82342 / inTopicNo.15)  Re[8]: VBでCRC32を高速で計算する方法
□投稿者/ ぎゅんぎゅ (11回)-(2017/01/04(Wed) 13:47:49)
Hongliangさん

モジュールに分けてOption Strict Onをしてみましたが
計算速度に違いは見られませんでした。

WebSurferさん
Professional版だと
ソリューションエクスプローラー
で Properties を右クリックして開いて[ビルド]タブ
にあるのかも知れませんが
Express版だとそこに設定がないのですが・・・
vbprojファイルを直接いじる方法をご存じでしたら教えてください

引用返信 編集キー/
■82343 / inTopicNo.16)  Re[9]: VBでCRC32を高速で計算する方法
□投稿者/ Jitta (246回)-(2017/01/04(Wed) 14:10:34)
2017/01/04(Wed) 14:21:48 編集(投稿者)

No82342 (ぎゅんぎゅ さん) に返信

どこに時間がかかっていますか?
手元の環境で実行しました。
32ビットCPU 、567MBのファイル対象で約9秒でした。
しかし、StopWatch クラスで計測場所を変えてみると、
計算は約4秒、後はファイル読み込みでした。
計算は、アルゴリズムの調整でなんとかなるかもしれませんが、
ファイル読み込みの時間はどうにもなりません。
一応、バッファサイズは4、8、16KBでやってみましたが、同じでした。

CPU設定は、64ビットCPUで32ビットモードの実行ファイルを動かしている、ということでなければ無視して構いません。
Expressなら、Any CPUになるはず。
引用返信 編集キー/
■82346 / inTopicNo.17)  Re[10]: VBでCRC32を高速で計算する方法
□投稿者/ ぎゅんぎゅ (13回)-(2017/01/04(Wed) 15:27:15)

ありがとうございます。

仰る通り、ファイルの読み込み速度が律速していると思いますが
DLLを使えばもう少し速度を改善できると思います。

それでDLLの呼び出し方を教えていただけないでしょうか?

http://blog.systemjp.net/entry/2014/03/19/212653

この方法を使って
VBで作成したDLLファイルは
VBで読み込むことができます。



http://www.codeexperts.com/showthread.php?93-How-to-CRC-file-in-C

それでこのページにあるコードをC#を使ってDLLを生成したものをVBで呼び出したいのですが
同様の方法を使ってもうまくいきません。

Dim obj As New ClassLibrary1.Class1()
Dim obj As New ClassLibrary1.Program()
Dim obj As New ClassLibrary1.crc()
などを試してみましたが、エラーが出てしまいます。

散々、検索して調べましたが
VBからのC#のDLLの呼び出し方がよく分かりませんでした。


どうすれば良いでしょうか?


引用返信 編集キー/
■82347 / inTopicNo.18)  Re[11]: VBでCRC32を高速で計算する方法
□投稿者/ Azulean (760回)-(2017/01/04(Wed) 15:47:40)
No82346 (ぎゅんぎゅ さん) に返信
> http://www.codeexperts.com/showthread.php?93-How-to-CRC-file-in-C
>
> それでこのページにあるコードをC#を使ってDLLを生成したものをVBで呼び出したいのですが
> 同様の方法を使ってもうまくいきません。

基本的に、同じプロジェクト以外からは呼べない internal と呼ばれる可視性が C# のデフォルトになっています。
プロジェクトの外から使えるようにするためには、クラスやメソッドに public という可視性を付与する必要があります。

https://msdn.microsoft.com/ja-jp/library/ms173121.aspx
引用返信 編集キー/
■82348 / inTopicNo.19)  Re[12]: VBでCRC32を高速で計算する方法
□投稿者/ ぎゅんぎゅ (14回)-(2017/01/04(Wed) 16:17:42)
ありがとうございます。


public class Program
{
static uint[] crc32_table = new uint[256];
static uint ulPolynomial = 0x04c11db7;


public static void Main2(string filepath)
{

のようにしてクラスやメソッド
publicをつけてみました

しかし
Dim obj As New ClassLibrary3.Program

としてもやはり見つからないというエラーが出るのですが


引用返信 編集キー/
■82349 / inTopicNo.20)  Re[13]: VBでCRC32を高速で計算する方法
 
□投稿者/ Jitta (248回)-(2017/01/04(Wed) 16:46:43)
4.1秒台だったのが3.7秒台になりましたが、
ファイル読み込みを足すと9秒台が15秒台になりました。
(C#のまま実行)
ムダだと思いますよ。
引用返信 編集キー/

このトピックをツリーで一括表示

次の20件>
トピック内ページ移動 / << 0 | 1 | 2 | 3 | 4 >>

管理者用

- Child Tree -