ファイル読込の速度比較 <TOP>
ファイルの読込速度(通常のテキストファイル読込と、ファイルマッピングを使った読込)を比較します。
GetFileTitle パスからファイル名を取得 GetFileSize ファイルのサイズをバイト単位で取得 CloseHandle オープンされているオブジェクトハンドルをクローズ CreateFile 指定したファイルをオープンし、デバイスハンドルを返す(ファイルサイズ取得用) CreateFileLong 指定したファイルをオープンし、デバイスハンドルを返す(マッピング読込用) CreateFileMapping ファイルマッピングオブジェクトを作成 MapViewOfFile ファイルビューをマッピング OpenFileMapping 名前付きファイルマッピングオブジェクトをオープン UnmapViewOfFile ファイルのマップビューをアンマップ GetTickCount システムが起動してからの経過時間を取得 MoveMemory メモリの指定領域をコピー
Text1にドラッグ&ドロップ、または「ファイルを開く」でテキストファイルを選択します。それぞれの読込ボタンでその処理時間を取得しています。
'================================================================ '= ファイル読込の速度比較 '= (OpenFileMapping.bas) '================================================================ #include "Windows.bi" #define FILE_MAP_COPY &H1 '上書きモード #define FILE_MAP_WRITE &H2 '読み書きモード #define FILE_MAP_READ &H4 '読み込み専用モード #define PAGE_READONLY &H2 'コミット済みのページ領域に対する読み取りアクセスを許可 #define PAGE_READWRITE &H4 'コミット済みのページ領域に対する読み取りアクセスと書き込みアクセスの両方を許可 #define PAGE_WRITECOPY &H8 'コピー可能アクセス(hFileは、GENERIC_READ属性を持たなければならない) #define GENERIC_READ -2147483648 '読み込みモード(&H80000000) #define GENERIC_WRITE &H40000000 '書き込みモード #define INVALID_HANDLE_VALUE -1 '見つからない場合 #define OPEN_EXISTING 3 'ファイルをオープンする(存在しない場合失敗) #define OPEN_ALWAYS 4 'ファイルをオープンする(存在しない場合作成) #define vbCrLf (Chr$(13) & Chr$(10)) 'キャリッジリターンとラインフィード(\r\n) ' セキュリティを定義する構造体 Type SECURITY_ATTRIBUTES nLength As Long lpSecurityDescriptor As Long bInheritHandle As Long End Type ' パスからファイル名を取得 Declare Function Api_GetFileTitle% Lib "comdlg32" Alias "GetFileTitleA" (ByVal lpszFile$, ByVal lpszTitle$, ByVal cbBuf%) ' ファイルのサイズをバイト単位で取得 Declare Function Api_GetFileSize& Lib "kernel32" Alias "GetFileSize" (ByVal hFile&, lpFileSizeHigh&) ' オープンされているオブジェクトハンドルをクローズ Declare Function Api_CloseHandle& Lib "kernel32" Alias "CloseHandle" (ByVal hObject&) ' 指定したファイルをオープンし、デバイスハンドルを返す(ファイルサイズ取得用) Declare Function Api_CreateFile& Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName$, ByVal dwDesiredAccess&, ByVal dwShareMode&, lpSecurityAttributes As SECURITY_ATTRIBUTES, ByVal dwCreationDistribution&, ByVal dwFlagsAttributes&, ByVal hTemplateFile&) ' 指定したファイルをオープンし、デバイスハンドルを返す(マッピング読込用) Declare Function Api_CreateFileLong& Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName$, ByVal dwDesiredAccess&, ByVal dwShareMode&, ByVal lpSecurityAttributes&, ByVal dwCreationDisposition&, ByVal dwFlagsAndAttributes&, ByVal hTemplateFile&) ' ファイルマッピングオブジェクトを作成 Declare Function Api_CreateFileMapping& Lib "kernel32" Alias "CreateFileMappingA" (ByVal hFile&, ByVal lpFileMappigAttributes&, ByVal flProtect&, ByVal dwMaximumSizeHigh&, ByVal dwMaximumSizeLow&, ByVal lpName$) ' ファイルビューをマッピング Declare Function Api_MapViewOfFile& Lib "kernel32" Alias "MapViewOfFile" (ByVal hFileMappingObject&, ByVal dwDesiredAccess&, ByVal dwFileOffsetHigh&, ByVal dwFileOffsetLow&, ByVal dwNumberOfBytesToMap&) ' 名前付きファイルマッピングオブジェクトをオープン Declare Function Api_OpenFileMapping& Lib "kernel32" Alias "OpenFileMappingA" (ByVal dwDesiredAccess&, ByVal bInheritHandle&, ByVal lpName$) ' ファイルのマップビューをアンマップ Declare Function Api_UnmapViewOfFile& Lib "kernel32" Alias "UnmapViewOfFile" (ByVal lpBaseAddress&) ' システムが起動してからの経過時間を取得 Declare Function Api_GetTickCount& Lib "kernel32" Alias "GetTickCount" () ' メモリの指定領域をコピー Declare Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" (Dest As Any, ByVal Source&, ByVal length&) Var Shared Edit1 As Object Var Shared Text(2) As Object Var Shared Button(2) As Object Edit1.Attach GetDlgItem("Edit1") : Edit1.SetFontSize 12 For i = 0 To 2 Text(i).Attach GetDlgItem("Text" & Trim$(Str$(i + 1))) : Text(i).SetFontSize 12 Button(i).Attach GetDlgItem("Button" & Trim$(Str$(i + 1))) : Button(i).SetFontSize 12 Next Var Shared PathName As String Var Shared FileLength As Long Var Shared sFile As Long '================================================================ '= '================================================================ Declare Sub MainForm_Start edecl () Sub MainForm_Start() Edit1.EnableWindow 0 Button(1).EnableWindow 0 Button(2).EnableWindow 0 End Sub '================================================================ '= ファイルマッピングを用いてファイルを高速に読み込む '================================================================ Declare Function FileReadByFileMapping(hFileName As String) As String Function FileReadByFileMapping(hFileName As String) As String Var hFileMap As Long Var hFile As Long Var hOpened As Long Var nAddress As Long Var buffer As String Var Buffer2 As String Var Ret As Long hFile = Api_CreateFileLong(hFileName, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0) hFileMap = Api_CreateFileMapping(hFile, 0, PAGE_READONLY, 0, 0, "test") If hFileMap = 0 Then Goto *ReadEnd hOpened = Api_OpenFileMapping(FILE_MAP_READ, 0, "test") If hOpened = 0 Then Goto *ReadEnd nAddress = Api_MapViewOfFile(hOpened, FILE_MAP_READ, 0, 0, 0) If nAddress = 0 Then Goto *ReadEnd buffer = String$(FileLength, Chr$(0)) MoveMemory buffer, nAddress, FileLength Buffer2 = Left$(buffer, InStr(buffer, Chr$(0))) Ret = Api_UnmapViewOfFile(nAddress) *ReadEnd Ret = Api_CloseHandle(hOpened) Ret = Api_CloseHandle(hFileMap) Ret = Api_CloseHandle(hFile) FileReadByFileMapping = Buffer2 End Function '================================================================ '= ファイルサイズ取得 '================================================================ Declare Sub FileSizeGet edecl () Sub FileSizeGet() Var hFileName As Long Var sa As SECURITY_ATTRIBUTES Var FileSizeLow As Long Var FileSizeHigh As Long Var Ret As Long Edit1.SetWindowtext "" Text(1).SetWindowtext "" Text(2).SetWindowtext "" 'セキュリティ構造体を初期化 sa.nLength = Len(sa) 'ファイルハンドル取得 hFileName = Api_CreateFile(PathName, GENERIC_READ, 0, sa, OPEN_EXISTING, 0, 0) 'ファイルハンドルの値が有効(見つかったとき) If hFileName <> INVALID_HANDLE_VALUE Then 'ファイルサイズを取得 FileSizeLow = Api_GetFileSize(hFileName, FileSizeHigh) 'ファイルサイズの取得に失敗したときは If FileSizeLow = &HFFFFFFFF Then '拡張エラー情報を表示 A% = MessageBox("", "取得に失敗しました。", 0, 2) Exit Sub Else 'ファイルサイズ FileLength = FileSizeLow + 1 End If 'ファイルをクローズ Ret = Api_CloseHandle(hFileName) '有効でないとき Else 'エラーを表示 A% = MessageBox("", "ファイルを開けませんでした。", 0, 2) End If End Sub '================================================================ '= シェルドロップされたファイル名を取得 '================================================================ Declare Sub Text1_DropFiles edecl (ByVal DF As Long) Sub Text1_DropFiles(ByVal DF As Long) Var CN As Long Edit1.EnableWindow -1 Button(1).EnableWindow -1 Button(2).EnableWindow -1 CN = GetDropFileCount(DF) PathName = GetDropFileName(DF, 0) Text(0).SetWindowText PathName 'ファイルサイズ取得 FileSizeGet Text(1).SetWindowText format$(FileLength - 1, "###,###,### byte ") End Sub '================================================================ '= ファイルを開く '================================================================ Declare Sub Button1_on edecl () Sub Button1_on() Var Buffer As String Var Ret As Integer Edit1.SetWindowText "" Text(0).SetWindowText "" Text(1).SetWindowText "" Text(2).SetWindowText "" PathName = WinOpenDlg("ファイルのオープン","*.txt;*.csv;*.bas","テキストファイル(*.txt);csvファイル(*.csv);basファイル(*.bas)", 0) If PathName <> Chr$(&H1B) Then Edit1.EnableWindow -1 Button(1).EnableWindow -1 Button(2).EnableWindow -1 Buffer = String$(255, 0) Ret = Api_GetFileTitle(PathName, Buffer, Len(Buffer)) Buffer = Left$(Buffer, InStr(1, Buffer, Chr$(0)) - 1) Text(0).SetWindowText " " & Buffer 'ファイルサイズ取得 FileSizeGet Text(1).SetWindowText format$(FileLength - 1, "###,###,### byte ") Else Edit1.EnableWindow 0 Button(1).EnableWindow 0 Button(2).EnableWindow 0 End If End Sub '================================================================ '= ファイルマッピングによる読込 '================================================================ Declare Sub Button2_on edecl () Sub Button2_on() Var t As Long Var buffer As String Edit1.SetWindowText "" Text(2).SetWindowText "" '計測開始 SetMousePointer 2 t = Api_GetTickCount buffer = FileReadByFileMapping(PathName) Edit1.SetWindowText buffer '計測終了 SetMousePointer 0 Text(2).SetWindowText " 読込表示処理時間:" & Str$((Api_GetTickCount - t) / 1000) & "秒" End Sub '================================================================ '= 通常の読込 '================================================================ Declare Sub Button3_on edecl () Sub Button3_on() Var ff As Integer Var t As Long Var txt As String Var temp As String Edit1.SetWindowText "" Text(2).SetWindowText "" '計測開始 SetMousePointer 2 t = Api_GetTickCount ff = FreeFile Open PathName For Input As #ff Do While Not Eof(#ff) Line Input #ff, temp txt = txt & temp & vbCrLf Loop Close #ff Edit1.SetWindowText txt '計測終了 SetMousePointer 0 Text(2).SetWindowText " 読込表示処理時間:" & Str$((Api_GetTickCount - t) / 1000) & "秒" End Sub '================================================================ '= '================================================================ While 1 WaitEvent Wend Stop End