VBA 8バイト符号なし整数
投稿者 るきお  (社会人)
投稿日時
2023/11/12 22:54:12
Excelの32ビット版と64ビット版でVBAにどういう差異があるのか理解していませんが、
> (Highを32bit左シフト)+ Low でいいと思うのですが、VBAでのコーディングがわかりません。
私はこういうビット演算が苦手なので、こういう系はByte型にして、地道にしたからかけ算して足していきます。
この考え方は32ビットでも64ビットでも同じです。
なので、fileSizeの部分はこのようにByteの配列にしてしまって、
取得したあとで、これをこんな感じで計算します。
かっこよくビット演算すればもっとスマートに行けるとは思いますが…。
参考に64ビット版ではありますが、動作確認したコードを載せておきます。約60GBのファイルでサイズを取得できることを確認しました。
ひさしぶりにExcel VBAを書きました。知らない間に LongLong などという型ができていたんですね。が、これは32ビット版にはないようだったので、一応ここはVariant(Decimal)にしておきました。
> (Highを32bit左シフト)+ Low でいいと思うのですが、VBAでのコーディングがわかりません。
私はこういうビット演算が苦手なので、こういう系はByte型にして、地道にしたからかけ算して足していきます。
この考え方は32ビットでも64ビットでも同じです。
なので、fileSizeの部分はこのようにByteの配列にしてしまって、
fileSizeHigh(3) As Byte
fileSizeLow(3) As Byte
取得したあとで、これをこんな感じで計算します。
fileSizeB = CDec(data.fileSizeLow(0))
fileSizeB = fileSizeB + data.fileSizeLow(1) * 256
fileSizeB = fileSizeB + data.fileSizeLow(2) * 256 ^ 2
fileSizeB = fileSizeB + data.fileSizeLow(3) * 256 ^ 3
…
かっこよくビット演算すればもっとスマートに行けるとは思いますが…。
参考に64ビット版ではありますが、動作確認したコードを載せておきます。約60GBのファイルでサイズを取得できることを確認しました。
ひさしぶりにExcel VBAを書きました。知らない間に LongLong などという型ができていたんですね。が、これは32ビット版にはないようだったので、一応ここはVariant(Decimal)にしておきました。
Private Const MAX_PATH As Long = 260
Private Declare PtrSafe Function FindFirstFile Lib "kernel32" Alias "FindFirstFileW" _
(ByVal lpFileName As LongPtr, _
ByRef FindData As WIN32_FIND_DATAW) As LongPtr
Private Type FILETIME
dwLowDateTime As Long
dwHighDateTime As Long
End Type
Private Type WIN32_FIND_DATAW
dwFileAttributes As Long
ftCreationTime As FILETIME
ftLastAccessTime As FILETIME
ftLastWriteTime As FILETIME
fileSizeHigh(3) As Byte
fileSizeLow(3) As Byte
dwReserved0 As Long
dwReserved1 As Long
cFileName(MAX_PATH * 2 - 1) As Byte
cAlternateFileName(14 * 2 - 1) As Byte
dwFileType As Long
dwCreatorType As Long
wFinderFlags As Integer
End Type
Public Sub FindFirstFileTest()
Dim data As WIN32_FIND_DATAW
Dim fileName As String
fileName = "C:\VM\Windows7.vhd"
Call FindFirstFile(StrPtr(fileName), data)
Dim fileSizeB As Variant
fileSizeB = CDec(data.fileSizeLow(0))
fileSizeB = fileSizeB + data.fileSizeLow(1) * 256
fileSizeB = fileSizeB + data.fileSizeLow(2) * 256 ^ 2
fileSizeB = fileSizeB + data.fileSizeLow(3) * 256 ^ 3
fileSizeB = fileSizeB + data.fileSizeHigh(0) * 256 ^ 4
fileSizeB = fileSizeB + data.fileSizeHigh(1) * 256 ^ 5
fileSizeB = fileSizeB + data.fileSizeHigh(2) * 256 ^ 6
fileSizeB = fileSizeB + data.fileSizeHigh(3) * 256 ^ 7
Dim fileSizeKB As Variant
fileSizeKB = CDec(fileSizeB) / 1024
Debug.Print fileSizeKB
End Sub
投稿者 KOZ  (社会人)
投稿日時
2023/11/12 23:21:24
るきおさんの方法ってわかりやすくていいですね。
nFileSizeHigh As Long
nFileSizeLow As Long
の部分を Currency (8ビット2進数)でとって 10000 倍するという方法もあります。
nFileSizeHigh As Long
nFileSizeLow As Long
の部分を Currency (8ビット2進数)でとって 10000 倍するという方法もあります。
投稿者 KOZ  (社会人)
投稿日時
2023/11/12 23:22:57
まちがえた!8ビットでなくて8バイト2進数です。
投稿者 KOZ  (社会人)
投稿日時
2023/11/12 23:28:48
正攻法なら
かなー
Sub main()
Debug.Print GetFileSize(2, -2147483648@) / 1024; "KB"
End Sub
Function GetFileSize(ByVal nHigh As Long, ByVal nLow As Long) As Variant
GetFileSize = CDec(ToUint32(nHigh)) * (2 ^ 32) + ToUint32(nLow)
End Function
Function ToUint32(ByVal value As Long) As Currency
Dim tmp As Currency
If value > 0 Then
ToUint32 = value
Else
ToUint32 = 4294967295@ + value + 1
End If
End Function
かなー
投稿者 てつ  (社会人)
投稿日時
2023/11/13 00:30:11
るきお様、KOZ様、こんなに早く返信頂き、ありがとうございます。
どちらの方法でも、希望結果を取得できました。
「Decimal、Currencyあたりを使うのかな」程度の知識しかなく、VBAでのコーディングが解らなかったので助かりました。
どうもありがとうございました。
どちらの方法でも、希望結果を取得できました。
「Decimal、Currencyあたりを使うのかな」程度の知識しかなく、VBAでのコーディングが解らなかったので助かりました。
どうもありがとうございました。
Win32APIのFindFirstFileでファイル検索した時、第2引数のWIN32_FIND_DATAに
ファイルサイズがDWORDで「nFileSizeHigh」と「nFileSizeLow」で返ります。
このファイルサイズをVBAで取得したいです。
https://learn.microsoft.com/ja-jp/windows/win32/api/minwinbase/ns-minwinbase-win32_find_dataw
10GBのテストファイルを作って試したところ、以下の値が返りました。
「nFileSizeLow」-2147483648
「nFileSizeHigh」2
(Highを32bit左シフト)+ Low でいいと思うのですが、VBAでのコーディングがわかりません。
&H200000000+&H80000000=8,589,934,592+2,147,483,648=10,737,418,240/1024
希望結果はExplorerと同じ「10,485,760」KBです。