職場でちょっとしたプログラムを作っているのですが、機能追加などで改修することになり、バージョン管理の一環として、サムチェック値の計算ツールを作りたいと考えています。
要は、作成した実行ファイル(バイナリ)について、サム値を計算すればいいので、FCIVとか巷のフリーツールでもいいのですが、ExcelVBAの勉強を兼ねて色々アレンジしたいのでマクロ文でお願いします。
要求を満たすものが複数挙がった場合は、私の主観で点数分配します。
評価ポイントは以下の通りですが、質問あれば随時受け付けます。
よろしくお願い致します。
評価ポイント:
・動作が軽い事。
・可読性。自分で色々アレンジしたいので。コメント等も多ければ良いとは思いませんがわかりやすいコメントや構文は好評価。
・機能別にサブルーチン化されていること。たぶん個別にボタン割り付けて使うので。
仕様は以下の通りです。
★:必須
※:できれば
★ファイルの読み書きはWindows7上で動作すればOK。その他のOS対応は不要。
★Excel2010のVBAマクロ記述だけで動作が完結すること。
他のツールを呼び出すとかはNG。
★対象は バイナリファイル×1 複数ファイルとかフォルダ毎とかは不要。
★対象ファイルは、シートの特定箇所にファイル名を記載して指定する。
※そのExcelファイルが置かれたパスを検出してくれるか、選択用のダイアログが出ると便利。
★サムチェック値は32bitのHEX表現で、特定のシートに出力される。
※マクロ実行する毎に次の行へ書き込んでくれると嬉しい。
★サム値の計算アルゴリズムは任意。
改ざん防止や保安度については考慮しなくてよい。
★処理速度優先。ファイルの中身が同じなら毎回同じサム値を出す。
これができれば複雑な演算は不要。
※最悪、単純加算でもOKだが、データを2箇所変更するとサム値が同じになってもうたとかそういうのが回避されるとちょっとだけ嬉しい。
★複数のアルゴリズムを切り替える機能は不要。
(どれでやったかわからなくなるので実装禁止)
★対象となるファイルのサイズは変動あり。固定長で処理を中断しないこと。
<Sheet1 の内容>
A | B | |
---|---|---|
1 | C:\Data\Tools\FCIV\fciv.exe |
[コマンドボタン]
<Sheet1 / コマンドボタンクリック時処理>
' ボタンクリック時にシートに記載したファイルのハッシュ値を取得する Private Sub CommandButton1_Click() Dim strFileName strFileName = Range("A1").Value Dim strMD5 strMD5 = GetFileHashMD5(strFileName) ' MD5 ハッシュ値128bit中32bitを表示する Range("B1").Value = Mid(strMD5, 24, 8) End Sub
<標準モジュール>
Option Explicit ' 指定したファイルの MD5 ハッシュ値を取得する Function GetFileHashMD5(strFileName) Dim md5 Set md5 = CreateObject("System.Security.Cryptography.MD5CryptoServiceProvider") md5.ComputeHash_2 (ReadBinaryFile(strFileName)) Dim msxml Set msxml = CreateObject("MSXML2.DOMDocument") Dim el Set el = msxml.CreateElement("tmp") el.DataType = "bin.hex" el.NodeTypedValue = md5.Hash GetFileHashMD5 = el.Text End Function ' 指定したファイルのバイト配列を取得する Function ReadBinaryFile(strFileName) Const adTypeBinary = 1 Dim stm Set stm = CreateObject("ADODB.Stream") stm.Type = adTypeBinary stm.Open stm.LoadFromFile strFileName ReadBinaryFile = stm.Read End Function
<実行結果>
A | B | |
---|---|---|
1 | C:\Data\Tools\FCIV\fciv.exe | 4e9c07c6 |
<参考サイト>
■ WindowsでSHA1とMD5を調べる
http://d.hatena.ne.jp/papaking_ken/20110224/1298564016
対応要否 | 要求仕様 | 実装状況 | コメント |
---|---|---|---|
★ | ファイルの読み書きはWindows7上で動作すればOK。その他のOS対応は不要。 | △ | Windows10にて開発。バージョン依存する機能は未使用の為、Windows7でも動作すると思われる。 |
★ | Excel2010のVBAマクロ記述だけで動作が完結すること。 | △ | Excel2013にて開発。バージョン依存する機能は未使用の為、Excel2010でも動作すると思われる。 |
★ | 対象は バイナリファイル×1 複数ファイルとかフォルダ毎とかは不要。 | ○ | バイナリファイルにて確認済み |
★ | 対象ファイルは、シートの特定箇所にファイル名を記載して指定する。 | ○ | セルA1にファイル名を指定。ボタン押下にてマクロ起動 |
★ | サムチェック値は32bitのHEX表現で、特定のシートに出力される。 | ○ | MD5ハッシュ値128bitのうち32bitを出力。妥当性については未確認 |
★ | サム値の計算アルゴリズムは任意。 | ○ | MD5 |
★ | 処理速度優先。ファイルの中身が同じなら毎回同じサム値を出す。 | ○ | Crypto APIを使用している為、ネイティブ並みの処理速度を実現 |
★ | 複数のアルゴリズムを切り替える機能は不要。 | ○ | MD5のみを使用 |
★ | 対象となるファイルのサイズは変動あり。固定長で処理を中断しないこと。 | ○ | 任意のファイルサイズに対応。数百MBでも数秒でチェック可能 |
<Sheet1 の内容>
A | B | |
---|---|---|
1 | C:\Data\Tools\FCIV\fciv.exe |
[コマンドボタン]
<Sheet1 / コマンドボタンクリック時処理>
' ボタンクリック時にシートに記載したファイルのハッシュ値を取得する Private Sub CommandButton1_Click() Dim strFileName strFileName = Range("A1").Value Dim strMD5 strMD5 = GetFileHashMD5(strFileName) ' MD5 ハッシュ値128bit中32bitを表示する Range("B1").Value = Mid(strMD5, 24, 8) End Sub
<標準モジュール>
Option Explicit ' 指定したファイルの MD5 ハッシュ値を取得する Function GetFileHashMD5(strFileName) Dim md5 Set md5 = CreateObject("System.Security.Cryptography.MD5CryptoServiceProvider") md5.ComputeHash_2 (ReadBinaryFile(strFileName)) Dim msxml Set msxml = CreateObject("MSXML2.DOMDocument") Dim el Set el = msxml.CreateElement("tmp") el.DataType = "bin.hex" el.NodeTypedValue = md5.Hash GetFileHashMD5 = el.Text End Function ' 指定したファイルのバイト配列を取得する Function ReadBinaryFile(strFileName) Const adTypeBinary = 1 Dim stm Set stm = CreateObject("ADODB.Stream") stm.Type = adTypeBinary stm.Open stm.LoadFromFile strFileName ReadBinaryFile = stm.Read End Function
<実行結果>
A | B | |
---|---|---|
1 | C:\Data\Tools\FCIV\fciv.exe | 4e9c07c6 |
<参考サイト>
■ WindowsでSHA1とMD5を調べる
http://d.hatena.ne.jp/papaking_ken/20110224/1298564016
対応要否 | 要求仕様 | 実装状況 | コメント |
---|---|---|---|
★ | ファイルの読み書きはWindows7上で動作すればOK。その他のOS対応は不要。 | △ | Windows10にて開発。バージョン依存する機能は未使用の為、Windows7でも動作すると思われる。 |
★ | Excel2010のVBAマクロ記述だけで動作が完結すること。 | △ | Excel2013にて開発。バージョン依存する機能は未使用の為、Excel2010でも動作すると思われる。 |
★ | 対象は バイナリファイル×1 複数ファイルとかフォルダ毎とかは不要。 | ○ | バイナリファイルにて確認済み |
★ | 対象ファイルは、シートの特定箇所にファイル名を記載して指定する。 | ○ | セルA1にファイル名を指定。ボタン押下にてマクロ起動 |
★ | サムチェック値は32bitのHEX表現で、特定のシートに出力される。 | ○ | MD5ハッシュ値128bitのうち32bitを出力。妥当性については未確認 |
★ | サム値の計算アルゴリズムは任意。 | ○ | MD5 |
★ | 処理速度優先。ファイルの中身が同じなら毎回同じサム値を出す。 | ○ | Crypto APIを使用している為、ネイティブ並みの処理速度を実現 |
★ | 複数のアルゴリズムを切り替える機能は不要。 | ○ | MD5のみを使用 |
★ | 対象となるファイルのサイズは変動あり。固定長で処理を中断しないこと。 | ○ | 任意のファイルサイズに対応。数百MBでも数秒でチェック可能 |
必須項目について可能な範囲で対応しました。
実機による動作テストについては、手元に、Windows7+Excel2010環境が無い為、出来ていません。
お手数ですが、お手持ちの環境にて確認お願いします。
ありがとうございます。確認してみます。
チェックサムと言えばCRC32なので探し出しましたがスピードは遅いです。
たぶんライブラリ使ったid:cx20さんのにかなうのはないと思います。
※そのExcelファイルが置かれたパスを検出してくれるか、選択用のダイアログが出ると便利。
※マクロ実行する毎に次の行へ書き込んでくれると嬉しい。
この辺実装しました。
id:cx20さんのと組み合わせていただければ良いかと思います。
Option Explicit Const FileNameSheet = "ファイル名" Const FileNameCell = "A1" Const HashStoreSheet = "サム値" Const HashStoreColumn = "B" Dim Crc32Table&(255) ' Mainマクロを実行する Sub Main() Dim strFileName As String strFileName = GetFileName() Dim hash hash = GetCrc32FromFile(strFileName) hash = Hex(hash) 'hash = GetFileHashMD5(strFileName) 'hash = Mid(strHash, 24, 8) StoreResult hash End Sub Function GetFileName() ' カレントディレクトリをブックのあるフォルダにすることで絶対パス・相対パスどちらでも対応可能にする ' 参考: http://www.asahi-net.or.jp/~ef2o-inue/vba_o/sub05_110_140.html ChDrive ThisWorkbook.Path ChDir ThisWorkbook.Path ' 以下三種の取得方法 ' GetFileName = Sheets(FileNameSheet).Range(FileNameCell).Value ' 特定シートの特定セルから得る GetFileName = Range(FileNameCell).Value ' 現在のシートの特定位置のセルから得る ' GetFileName = Selection.Value ' 選択中のセルから得る End Function Sub StoreResult(strResult) Sheets(HashStoreSheet).Cells(Rows.Count, HashStoreColumn).End(xlUp).Item(2).Value = strResult ' Rows.Count 行の最大値 ' Cells(Rows.Count, "B") B列最終行のセル ' End(xlUp) 上方向(xlUp)でデータのある最初のセル(Ctrl+↑) ' 最終行のセル + Ctrl+↑ = データのある最後のセル ' Item(2) その下のセル(現在位置を(1)として上下に2番の位置) End Sub ' 以下コピペ ' http://d.hatena.ne.jp/n7shi/20100910/1284112553 ' https://code.msdn.microsoft.com/office/VBACRC-32-dad7d087 ' Dim I%, J%, R&, R1&等参考 ' http://www.atmarkit.co.jp/fdotnet/vb6tonet/vb6tonet30/vb6tonet30_01.html Private Sub InitCrc32Table() Dim I%, J%, R&, R1& For I = 0 To 255 R = I For J = 0 To 7 R1 = R And 1 R = (R - R1) / 2 If R < 0 Then R = R - &H80000000 If R1 Then R = R Xor &HEDB88320 Next J Crc32Table(I) = R Next I End Sub Public Function GetCrc32FromFile&(Path$) Dim R&, I&, B As Byte, FL& If Crc32Table(255) = 0 Then InitCrc32Table FL = FileLen(Path) Open Path For Binary Lock Read As #2 R = Not 0 For I = 1 To FL Get #2, , B R = (Int(R / 256) And &HFFFFFF) Xor Crc32Table((R Xor B) And &HFF) Next I Close #2 GetCrc32FromFile = Not R End Function
書いておいて何ですが、そういえば勉強用でしたね……
前半は数行で済む所を無駄に関数化してたり、後半は古い書き方だったりで、あまり向かない気もしてきました。
まあ、知識として知っておいた方が良い部分はあると思いますけども。
いえ、関数は小分けにしてもらえるほうがありがたいです。
つけたし、流用、はその方がやりやすいので。
必須項目について可能な範囲で対応しました。
2015/09/07 23:46:46実機による動作テストについては、手元に、Windows7+Excel2010環境が無い為、出来ていません。
お手数ですが、お手持ちの環境にて確認お願いします。
ありがとうございます。確認してみます。
2015/09/08 00:33:23