by イグトランス » 2006年1月09日(月) 16:13
さらにその上を行く手段としてメモリマップドファイルと言うものがあります。
ようするにファイルを巨大なByte配列と見なして処理ができると言うことです。(Byte型に限らずなんでも良いですが)
もはやバッファとファイルとの読み書きなんて要りません。(裏でWindowsがよきに計らっているだけですが)
[ここをクリックすると内容が表示されます] [ここをクリックすると非表示にします]InputFileとOutputFileは適当に書き換えてください。
コード: 全て選択
#strict
#prompt
Const InputFile = "c:\temp\test_input.bin"
Const OutputFile = "c:\temp\test_output.bin"
Typedef BOOL = Long
timeBeginPeriod(1)'精度を1msに設定
Dim Time As DWord
Time = timeGetTime()
If BinarySwap(InputFile, OutputFile) <> FALSE Then
Time = timeGetTime() - Time
Print Time ' 所要時間の表示
End If
timeEndPeriod(1)'timeBeginPeriodで指定した値を渡す
Function BinarySwap(pszInputFile As *Char, pszOutputFile As *Char) As BOOL
BinarySwap = FALSE
' 入力ファイルのファイルマッピングオブジェクトを作成。
Dim Input As egtra_FileMapping(pszInputFile, FALSE, OPEN_EXISTING)
If Input.GetFileHandle() = INVALID_HANDLE_VALUE Then
Print "入力ファイルが開けませんでした。"
Exit Function
End If
' 入力ファイルのサイズを取得。
Dim qwFileSize As QWord, pSize As *ULARGE_INTEGER
pSize = VarPtr(qwFileSize)
pSize->LowPart = GetFileSize(Input.GetFileHandle(), VarPtr(pSize->HighPart))
If pSize->LowPart = &hffffffff And GetLastError() <> 0 Then
Print "ファイルサイズが取得できませんでした。"
Exit Function
End If
#ifndef _WIN64
If pSize->HighPart <> 0 Then
Print "このプログラムは,Win32ではこんなに巨大なファイルに対応していません。"
Exit Function
End If
#endif
' 出力ファイルのファイルマッピングオブジェクトを作成。入力ファイルと同じ大きさに設定。
Dim Output As egtra_FileMapping(pszOutputFile, TRUE, CREATE_ALWAYS, pSize->HighPart, pSize->LowPart)
If Input.GetFileHandle() = INVALID_HANDLE_VALUE Then
Print "出力ファイルが開けませんでした。"
Exit Function
End If
' ここで実際にメモリアドレスへ割り当てている。
Dim pInput As *Byte, pOutput As *Byte
pInput = Input.MapView()
pOutput = Output.MapView()
'
'* スワップ処理(1⇔2,3⇔4・・・・)
'
Dim FileSize As ULONG_PTR
FileSize = qwFileSize As ULONG_PTR
Dim i As ULONG_PTR
For i = 0 To FileSize - 1 Step 2
pOutput = pInput[i + 1]
pOutput[i + 1] = pInput
Next
' マッピングの解除
Input.UnmapView(pInput)
Output.UnmapView(pOutput)
BinarySwap = TRUE
End Function
さらにこれも必要です。 [ここをクリックすると内容が表示されます] [ここをクリックすると非表示にします]コード: 全て選択
Declare Function timeGetTime Lib "winmm" () As DWord
Declare Function timeBeginPeriod Lib "winmm" (uPeriod As DWord) As Long
Declare Function timeEndPeriod Lib "winmm" (uPeriod As DWord) As Long
Declare Function CreateFileMapping Lib "kernel32" Alias "CreateFileMappingA" (
hFile As HANDLE,
pAttributes As *SECURITY_ATTRIBUTES,
flProtect As DWord,
dwMaximumSizeHigh As DWord,
dwMaximumSizeLow As DWord,
pName As *Char
) As HANDLE
Declare Function MapViewOfFile Lib "kernel32" (
hFileMappingObject As HANDLE,
dwDesiredAccess As DWord,
dwFileOffsetHigh As DWord,
dwFileOffsetLow As DWord,
NumberOfBytesToMap As SIZE_T
) As VoidPtr
Declare Function UnmapViewOfFile Lib "kernel32" (pBaseAddress As VoidPtr) As Long
/*
Const PAGE_READONLY = &H2
Const PAGE_READWRITE = &H4
*/
Const FILE_MAP_READ = &H4
Const FILE_MAP_WRITE = &H2
'簡易ファイルマッピングクラス
Class egtra_FileMapping
Public
Sub egtra_FileMapping(pszFileName As *Char, canWrite As Long, CreationDisposition As DWord)(FileSizeHigh As DWord, FileSizeLow As DWord)
Dim CreateFileFlag As DWord, CreateFileMappingFlag As DWord
If canWrite <> FALSE Then
CreateFileFlag = GENERIC_READ Or GENERIC_WRITE
CreateFileMappingFlag = PAGE_READWRITE
DesiredAccess = FILE_MAP_WRITE
Else
CreateFileFlag = GENERIC_READ
CreateFileMappingFlag = PAGE_READONLY
DesiredAccess = FILE_MAP_READ
End If
hFile = CreateFile(pszFileName, CreateFileFlag, 0, ByVal 0, CreationDisposition, 0, 0)
If hFile = INVALID_HANDLE_VALUE Then
Exit Sub
End If
hMap = CreateFileMapping(hFile, 0, CreateFileMappingFlag, FileSizeHigh, FileSizeLow, 0)
End Sub
Function MapView() As VoidPtr
MapView = MapViewOfFile(hMap, DesiredAccess, 0, 0, 0)
End Function
/*
Function MapView(dwFileOffsetHigh As DWord, dwFileOffsetLow As DWord, NumberOfBytesToMap As SIZE_T) As VoidPtr
MapView = MapViewOfFile(hMap, DesiredAccess, dwFileOffsetHigh, dwFileOffsetLow, NumberOfBytesToMap)
End Function
*/
Sub UnmapView(pv As VoidPtr) ' 本当は不要だが
UnmapViewOfFile(pv)
End Sub
Function GetFileHandle() As HANDLE
GetFileHandle = hFile
End Function
Sub ~egtra_FileMapping()
CloseHandle(hMap)
CloseHandle(hFile)
End Sub
Private
hFile As HANDLE
hMap As HANDLE
DesiredAccess As DWord
End Class
これで、omasuさんのものに比べおよそ半分の時間で実行できました。
(omasuさんのコードの前後にtimeGetTimeを挟んで計測しました。)
私のPCではおよそ80MiBytesのファイルでomasuさんのがおよそ3.2秒ほど,私のが1.6秒ほどでした。
さらにその上を行く手段としてメモリマップドファイルと言うものがあります。
ようするにファイルを巨大なByte配列と見なして処理ができると言うことです。(Byte型に限らずなんでも良いですが)
もはやバッファとファイルとの読み書きなんて要りません。(裏でWindowsがよきに計らっているだけですが)
[hide]InputFileとOutputFileは適当に書き換えてください。[code]#strict
#prompt
Const InputFile = "c:\temp\test_input.bin"
Const OutputFile = "c:\temp\test_output.bin"
Typedef BOOL = Long
timeBeginPeriod(1)'精度を1msに設定
Dim Time As DWord
Time = timeGetTime()
If BinarySwap(InputFile, OutputFile) <> FALSE Then
Time = timeGetTime() - Time
Print Time ' 所要時間の表示
End If
timeEndPeriod(1)'timeBeginPeriodで指定した値を渡す
Function BinarySwap(pszInputFile As *Char, pszOutputFile As *Char) As BOOL
BinarySwap = FALSE
' 入力ファイルのファイルマッピングオブジェクトを作成。
Dim Input As egtra_FileMapping(pszInputFile, FALSE, OPEN_EXISTING)
If Input.GetFileHandle() = INVALID_HANDLE_VALUE Then
Print "入力ファイルが開けませんでした。"
Exit Function
End If
' 入力ファイルのサイズを取得。
Dim qwFileSize As QWord, pSize As *ULARGE_INTEGER
pSize = VarPtr(qwFileSize)
pSize->LowPart = GetFileSize(Input.GetFileHandle(), VarPtr(pSize->HighPart))
If pSize->LowPart = &hffffffff And GetLastError() <> 0 Then
Print "ファイルサイズが取得できませんでした。"
Exit Function
End If
#ifndef _WIN64
If pSize->HighPart <> 0 Then
Print "このプログラムは,Win32ではこんなに巨大なファイルに対応していません。"
Exit Function
End If
#endif
' 出力ファイルのファイルマッピングオブジェクトを作成。入力ファイルと同じ大きさに設定。
Dim Output As egtra_FileMapping(pszOutputFile, TRUE, CREATE_ALWAYS, pSize->HighPart, pSize->LowPart)
If Input.GetFileHandle() = INVALID_HANDLE_VALUE Then
Print "出力ファイルが開けませんでした。"
Exit Function
End If
' ここで実際にメモリアドレスへ割り当てている。
Dim pInput As *Byte, pOutput As *Byte
pInput = Input.MapView()
pOutput = Output.MapView()
'
'* スワップ処理(1⇔2,3⇔4・・・・)
'
Dim FileSize As ULONG_PTR
FileSize = qwFileSize As ULONG_PTR
Dim i As ULONG_PTR
For i = 0 To FileSize - 1 Step 2
pOutput[i] = pInput[i + 1]
pOutput[i + 1] = pInput[i]
Next
' マッピングの解除
Input.UnmapView(pInput)
Output.UnmapView(pOutput)
BinarySwap = TRUE
End Function[/code]さらにこれも必要です。[hide][code]Declare Function timeGetTime Lib "winmm" () As DWord
Declare Function timeBeginPeriod Lib "winmm" (uPeriod As DWord) As Long
Declare Function timeEndPeriod Lib "winmm" (uPeriod As DWord) As Long
Declare Function CreateFileMapping Lib "kernel32" Alias "CreateFileMappingA" (
hFile As HANDLE,
pAttributes As *SECURITY_ATTRIBUTES,
flProtect As DWord,
dwMaximumSizeHigh As DWord,
dwMaximumSizeLow As DWord,
pName As *Char
) As HANDLE
Declare Function MapViewOfFile Lib "kernel32" (
hFileMappingObject As HANDLE,
dwDesiredAccess As DWord,
dwFileOffsetHigh As DWord,
dwFileOffsetLow As DWord,
NumberOfBytesToMap As SIZE_T
) As VoidPtr
Declare Function UnmapViewOfFile Lib "kernel32" (pBaseAddress As VoidPtr) As Long
/*
Const PAGE_READONLY = &H2
Const PAGE_READWRITE = &H4
*/
Const FILE_MAP_READ = &H4
Const FILE_MAP_WRITE = &H2
'簡易ファイルマッピングクラス
Class egtra_FileMapping
Public
Sub egtra_FileMapping(pszFileName As *Char, canWrite As Long, CreationDisposition As DWord)(FileSizeHigh As DWord, FileSizeLow As DWord)
Dim CreateFileFlag As DWord, CreateFileMappingFlag As DWord
If canWrite <> FALSE Then
CreateFileFlag = GENERIC_READ Or GENERIC_WRITE
CreateFileMappingFlag = PAGE_READWRITE
DesiredAccess = FILE_MAP_WRITE
Else
CreateFileFlag = GENERIC_READ
CreateFileMappingFlag = PAGE_READONLY
DesiredAccess = FILE_MAP_READ
End If
hFile = CreateFile(pszFileName, CreateFileFlag, 0, ByVal 0, CreationDisposition, 0, 0)
If hFile = INVALID_HANDLE_VALUE Then
Exit Sub
End If
hMap = CreateFileMapping(hFile, 0, CreateFileMappingFlag, FileSizeHigh, FileSizeLow, 0)
End Sub
Function MapView() As VoidPtr
MapView = MapViewOfFile(hMap, DesiredAccess, 0, 0, 0)
End Function
/*
Function MapView(dwFileOffsetHigh As DWord, dwFileOffsetLow As DWord, NumberOfBytesToMap As SIZE_T) As VoidPtr
MapView = MapViewOfFile(hMap, DesiredAccess, dwFileOffsetHigh, dwFileOffsetLow, NumberOfBytesToMap)
End Function
*/
Sub UnmapView(pv As VoidPtr) ' 本当は不要だが
UnmapViewOfFile(pv)
End Sub
Function GetFileHandle() As HANDLE
GetFileHandle = hFile
End Function
Sub ~egtra_FileMapping()
CloseHandle(hMap)
CloseHandle(hFile)
End Sub
Private
hFile As HANDLE
hMap As HANDLE
DesiredAccess As DWord
End Class[/code][/hide][/hide]
これで、omasuさんのものに比べおよそ半分の時間で実行できました。
(omasuさんのコードの前後にtimeGetTimeを挟んで計測しました。)
私のPCではおよそ80MiBytesのファイルでomasuさんのがおよそ3.2秒ほど,私のが1.6秒ほどでした。