Unicode対応のTFileStream。
unit myStream;
interface
uses
Classes,
SysUtils,
Windows;
type
TFileStreamW =
class(THandleStream)
public
constructor Create(
const FileName:
WideString; Mode: Word);
destructor Destroy;
override;
end;
implementation
uses
RTLConsts;
{TFileStreamW}
constructor TFileStreamW.Create(
const FileName:
WideString; Mode: Word);
//TFileStreamのUnicode版
var
li_AccessMode, li_ShareMode: DWORD;
begin
if (Mode = fmCreate)
then begin
inherited Create(CreateFileW(
PWideChar(FileName),
//ファイル名
GENERIC_READ
or GENERIC_WRITE,
//アクセスモード
0,
//共有モード
nil,
//セキュリティ
OPEN_ALWAYS,
//作成方法
FILE_ATTRIBUTE_NORMAL,
//ファイル属性
0
//テンプレート
));
end else begin
//アクセスモード
li_AccessMode := GENERIC_READ;
if ((Mode
and fmOpenWrite) <> 0)
then li_AccessMode := li_AccessMode
or GENERIC_WRITE;
{$WARN SYMBOL_PLATFORM OFF}
//共有モード
li_ShareMode := 0;
if (Mode >= fmShareExclusive)
then Dec(Mode, $10);
if ((Mode
and (fmShareDenyRead - $10)) <> 0)
then begin
//読み込みは禁止=書き込みはOK
li_ShareMode := FILE_SHARE_WRITE;
end;
if ((Mode
and (fmShareDenyWrite - $10)) <> 0)
then begin
//書き込みは禁止=読み込みはOK
li_ShareMode := li_ShareMode
or FILE_SHARE_READ;
end;
{$WARN SYMBOL_PLATFORM ON}
inherited Create(CreateFileW(
PWideChar(FileName),
li_AccessMode,
li_ShareMode,
nil,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0
));
end;
if (FHandle = Integer(INVALID_HANDLE_VALUE))
then begin
//エラーメッセージはUnicode対応ではない。
raise EFCreateError.CreateResFmt(@SFCreateError, [FileName]);
end;
end;
destructor TFileStreamW.Destroy;
begin
if (FHandle >= 0)
then CloseHandle(FHandle);
inherited Destroy;
end;
THandleStreamを継承してCreateFileW APIの戻り値をTHandleStreamのCreateの引数に渡すだけです。
あっけないくらい簡単にできてしまいます。
ところでDelphiの場合ファイルの共有モードは許可しない指定をします。
fmShareDenyWrite |
他のアプリケーションは読み出し用にファイルを開くことはできるが,書き込み用に開くことはできない |
fmShareDenyRead |
他のアプリケーションは書き込み用にファイルを開くことはできるが,読み出し用に開くことはできない |
fmShareDenyNone |
他のアプリケーションからのファイルの読み出しおよび書き込みを妨げる処理は行われない |
fmShareDenyWriteやfmShareDenyReadはまだしもfmShareDenyNoneになると意味としては「許可しないのはない」ということになるのでしょうが、分かりにくい表現になってしまっています。
CreateFile APIのように許可する共有を指定するようにした方が素直で分かりやすいのではないかと思います。
ということでCreateの引数の指定の仕方を変えた版を。
interface
uses
Classes,
SysUtils,
Windows;
type
TMyFileStream = class(THandleStream)
public
constructor Create(FileName: WideString; AccessMode, ShareMode: DWORD); overload;
constructor Create(FileName: WideString); overload;
destructor Destroy; override;
end;
implementation
uses
RTLConsts;
//------------------------------------------------------------------------------
{TMyFileStream}
constructor TMyFileStream.Create(FileName: WideString; AccessMode, ShareMode: DWORD);
//引数の指定の仕方を変えた版
var
li_CreateMode: DWORD;
begin
if ((AccessMode and GENERIC_WRITE) <> 0) then begin
li_CreateMode := OPEN_ALWAYS;
end else begin
li_CreateMode := OPEN_EXISTING;
end;
inherited Create(CreateFileW(
PWidechar(FileName), //ファイル名
AccessMode, //アクセスモード
ShareMode, //共有モード
nil, //セキュリティ
li_CreateMode, //作成方法
FILE_ATTRIBUTE_NORMAL, //ファイル属性
0 //テンプレート
));
end;
constructor TMyFileStream.Create(FileName: WideString);
begin
Create(FileName, GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE);
end;
destructor TMyFileStream.Destroy;
begin
if (FHandle >= 0) then CloseHandle(FHandle);
inherited Destroy;
end;
AccessModeとShareModeはCreateFile APIの指定そのままです。
AccessModeには読み込みか書き込みかあるいはその両方かをGENERIC_READとGENERIC_WRITEの組み合わせで指定します。
ShareModeには共有するモードをFILE_SHARE_READとFILE_SHARE_WRITEの組み合わせで指定します。
2009-01-14: