16番会議室「玉石混淆みんなで作るSample蔵」に寄せられたサンプル
"メモリマップトファイル(ストリーム)"
この発言に対し以下のコメントが寄せられています
#00028 ぜえた さん RE:メモリマップトファイル(ストリーム)
メモリマップトファイルを使うためのストリームです。
Memoryプロパティがファイルがマップされたメモリの先頭へのポインタです。
Create の仕方は TFileStream、その後の使い方は TMemoryStream と同じです。
ただし、Createのパラメータ Mode はファイルオープン定数ですが、
fmOpenWrite は指定できません。書き込みだけのメモリは設定できないからです。
メモリマップトファイルの利点
1:ファイルをメモリと同様に扱える。
インターフェースを別々に用意しなくてよい。
2:OSのキャッシュのおかげで、そこそこ速い。
3:メモリに大量のデータをファイルから読み込ませてスワップが発生したとき
ディスク上に同じデータが2つ出来て無駄であるが、それがなくなる。
など。
メモリマップトファイルの欠点
1:いつディスクI/Oが発生するかわからない。
2:OSのキャッシュは賢くない。
3:非同期入出力をつかうことが出来ない。
など。
「メモリマップトファイルを使うな」Inside Windows (1996/10)
を参照してください。
#前発言の「共有メモリ」も参考にしてください。
---------------------------------------------------------------------------
unit Streams;
interface
uses Windows, SysUtils, Classes;
type
EFMappingError = class(Exception);
EFMCreateError = class(EFMappingError);
EFMViewError = class(EFMappingError);
TFileMappingMemoryStream = class(TMemoryStream)
private
FMode: WORD;
FFileHandle: HFILE;
FHandle: THandle;
protected
function Realloc(var NewCapacity: Longint): Pointer; override;
public
constructor Create(const FileName: string; Mode: Word);
destructor Destroy; override;
property FileHandle: HFILE read FFileHandle;
property Handle: THandle read FHandle;
end;
implementation
uses Consts;
{ TFileMappingMemoryStream }
constructor TFileMappingMemoryStream.Create(const FileName: string; Mode:
WORD);
begin
FMode := Mode;//先にファイルを開く
if FMode = fmCreate then begin
FMode := fmOpenReadWrite;
FFileHandle := FileCreate(FileName);
if FFileHandle = HFILE_ERROR then
raise EFCreateError.CreateResFmt(SFCreateError, [FileName]);
end else begin
FFileHandle := FileOpen(FileName, FMode);
if FFileHandle = HFILE_ERROR then
raise EFOpenError.CreateResFmt(SFOpenError, [FileName]);
end;
inherited Create;
SetSize(GetFileSize(FFileHandle, nil));
end;
destructor TFileMappingMemoryStream.Destroy;
begin
inherited Destroy;
if FFileHandle <> 0 then CloseHandle(FFileHandle);//後からファイルを閉じる
end;
function TFileMappingMemoryStream.Realloc(var NewCapacity: Longint): Pointer;
const
ProtectMode: array[0..2] of DWORD = (
PAGE_READONLY,
PAGE_READWRITE,
PAGE_READWRITE);
ViewAccessMode: array[0..2] of DWORD = (
FILE_MAP_READ,
FILE_MAP_WRITE,
FILE_MAP_WRITE);
begin
Result := Memory;
if NewCapacity <> Capacity then begin
if Capacity <> 0 then begin
UnmapViewOfFile(Memory);
CloseHandle(FHandle);
Result := nil;
end;
if NewCapacity <> 0 then begin
FHandle := CreateFileMapping(FFileHandle, nil,
ProtectMode[FMode and $0003], 0, NewCapacity, nil);
try
if FHandle = 0 then
raise EFMCreateError.Create('Could not resize file-mapping object');
Result := MapViewOfFile(FHandle, ViewAccessMode[FMode and $0003],
0, 0, NewCapacity);
if Result = nil then begin
CloseHandle(FHandle);
raise EFMViewError.Create('Could not map view of file');
end;
except //Reallocが失敗したとき元の大きさに戻す
FHandle := CreateFileMapping(FFileHandle, nil,
ProtectMode[FMode and $0003], 0, Capacity, nil);
if FHandle = 0 then raise;
Result := MapViewOfFile(FHandle, ViewAccessMode[FMode and $0003],
0, 0, Capacity);
if Result = nil then CloseHandle(FHandle);
raise;
end;
end;
end;
end;
end.
---------------------------------------------------------------------------
なお、Delphi2.0 では、TMemoryStream にバグがあります。
SetSize が失敗するとすべてのメモリが失われるというバグです。
ソースをお持ちのかたは次のように直してください(Delphi3 VCLより)。
procedure TMemoryStream.SetSize(NewSize: Longint);
begin
// Clear;//削除
if FPosition > NewSize then Seek(0, soFromEnd);//追加
SetCapacity(NewSize);
FSize := NewSize;
end;
ぜえた (QZC05100)
Original document by ぜえた 氏 ID:(QZC05100)
ここにあるドキュメントは NIFTY SERVEの Delphi Users' Forum の16番会議室「玉石混淆みんなで作るSample蔵」に投稿されたサンプルです。これらのサンプルはボーランド株式会社がサポートする公式のものではありません。また、必ずしも動作が検証されているものではありません。これらのサンプルを使用したことに起因するいかなる損害も投稿者、およびフォーラムスタッフはその責めを負いません。使用者のリスクの範疇でご使用下さい。
Copyright 1996-2002 Delphi Users' Forum
|