首页  编辑  

结构化文件存储

Tags: /超级猛料/Stream.File.流、文件和目录/流操作/   Date Created:

按如下方式使用:

var

   stgFile:TStgFile;

   stream:TStgStream;

   storage:TStorage;

begin

try

   stgFile := TStgFile.CreateFile( ... );

   storage := stgFile.CreateStorage( ... );

   ...

   stream := storage.CreateStream( ... );

   ...

except

   ...

end;

end;

************************************************************

STG File存取

// (c) Alex Konshin mailto:alexk@msmt.spb.su 02.12.97

{   HISTROY:

               2002-1-8 down from www.torry.net

               2002-1-9 Fix some error;

                                Add commit function to TStorage.

}

{

$Date: 2002/01/10 00:53:37 $

$Author: zhangjun $

$Revision: 1.1 $

}

unit Storages;

interface

uses

       SysUtils, Windows, Classes, Forms, ActiveX;

const

       stgmOpenReadWrite = {STGM_TRANSACTED or} STGM_READWRITE or STGM_SHARE_DENY_WRITE;

       stgmOpenRead = {STGM_TRANSACTED or} STGM_READ or STGM_SHARE_EXCLUSIVE;

       stgmCreate = { STGM_TRANSACTED or} STGM_CREATE or STGM_READWRITE or STGM_SHARE_EXCLUSIVE;

       stgmConvert = {STGM_TRANSACTED or} STGM_READWRITE or STGM_SHARE_EXCLUSIVE or STGM_CONVERT;

type

       TStorage = class;

       TStgStream  = class(TStream)

       protected

               FStream : IStream;

               FStorage : TStorage;

               FName, FPath : String;

   procedure SetSize( NewSize : Longint ); override;

               procedure SetName( Value : String); virtual;

               constructor Create( const AName : String; AStorage : TStorage; AStream : IStream );

       public

   function Read( var Buffer; Count : Longint ) : Longint; override;

   function Write( const Buffer; Count : Longint ) : Longint; override;

   function Seek( Offset : Longint; Origin : Word ) : Longint; override;

               destructor Destroy; override;

       published

               property Name : String read FName write SetName;

       end; { TStgStream  }

       TStorage = class

       protected

               FStorage : IStorage;

               FName, FPath : String;

               FParent : TStorage;

               FLockCount : LongInt;

               procedure SetName( Value : String); virtual;

               constructor Create( const AName : String; AParent : TStorage; AStorage : IStorage );

       public

               destructor Destroy; override; // 眢骓?桉镱朦珙忄螯 Close !

               procedure Close;

               function CreateStream( const AName : String; const Mode : DWord ) : TStgStream;

               function OpenStream( const AName : String; const Mode : DWord ) : TStgStream;

               function OpenCreateStream( const AName : String; const Mode : DWord ) : TStgStream;

               function CreateStorage( const AName : String; const Mode : DWord ) : TStorage;

               function OpenStorage( const AName : String; const Mode : DWord ) : TStorage;

               function OpenCreateStorage( const AName : String; const Mode : DWord; var bCreate : Boolean ) : TStorage;

               procedure RenameElement( const AOldName, ANewName : String );

//    STGTY_STORAGE      = 1,

//    STGTY_STREAM       = 2,

//    STGTY_LOCKBYTES    = 3,

//    STGTY_PROPERTY     = 4

               procedure EnumElements( AStrings : TStringList ; dwTypeNeed:DWORD);

       procedure Commit(cFlag:DWORD);

       published

               property Storage : IStorage read FStorage;

               property Name : String read FName write SetName;

               property Path : String read FPath;

       end; { TStorage }

       TStgFile = class(TStorage)

       protected

               FFileName : String;

               constructor Create( const AFileName : String; AStorage : IStorage );

       public

               class function CreateFile( const AFileName : String; const Mode : DWord ) : TStgFile;

               class function OpenFile( const AFileName : String; const Mode : DWord ) : TStgFile;

//                function Clone( const Mode : DWord ) : TStgFile;

       end; { TStgFile }

{function ModeToStgMode( const Mode : Word ) : DWORD;

// fmCreate                        Create a file with the given name. If a file with the given name exists, open the file in write mode.

// fmOpenRead                Open the file for reading only.

// fmOpenWrite        Open the file for writing only. Writing to the file completely replaces the current contents.

// fmOpenReadWrite        Open the file to modify the current contents rather than replace them.

//

// fmShareCompat                Sharing is compatible with the way FCBs are opened.

// fmShareExclusive        Other applications can not open the file for any reason.

// fmShareDenyWrite        Other applications can open the file for reading but not for writing.

// fmShareDenyRead        Other applications can open the file for writing but not for reading.

// fmShareDenyNone        No attempt is made to prevent other applications from reading from or writing to the file.

function OpenStream( const APath : String; const Mode : Word ) : TStream; // Open plain file or IStream as TStream

function OpenStorage( const APath : String; const Mode : Word ) : TStorage;

}

//=============================================================

implementation

uses ComObj;

//=============================================================

//  fmCreate         = $ffff;

//  fmOpenRead       = $0000;

//  fmOpenWrite      = $0001;

//  fmOpenReadWrite  = $0002;

//  fmShareCompat    = $0000;

//  fmShareExclusive = $0010;

//  fmShareDenyWrite = $0020;

//  fmShareDenyRead  = $0030;

//  fmShareDenyNone  = $0040;

function ModeToStgMode( const Mode : Word ) : DWORD;

const

               RWModes : Array [0..3] of DWord = (STGM_READ,STGM_WRITE,STGM_READWRITE,0);

               ShareModes : Array [0..7] of DWord =

               (        STGM_SHARE_EXCLUSIVE,STGM_SHARE_EXCLUSIVE,STGM_SHARE_DENY_WRITE,STGM_SHARE_DENY_READ,

                       STGM_SHARE_DENY_NONE,STGM_SHARE_EXCLUSIVE,STGM_SHARE_EXCLUSIVE,STGM_SHARE_EXCLUSIVE);

begin

       if Mode=fmCreate then Result := stgmCreate

       else Result := RWModes[Mode and 3] or ShareModes[Mode shr 4];

end;

//-------------------------------------------------------------

{function GetName( var ptr : PChar; var len : Integer ) : String;

const Delimitors : String = '/\'#0;

var        i : Integer;

begin

       Result := '';

       i := QScanChars( ptr, len, Delimitors );

       if i>0 then

               begin

                       Dec(i);

                       if i=0 then Exit;

                       Result := Copy(ptr,1,i);

                       Inc(ptr,i);

                       Dec(len,i)

               end

       else

         begin

                 Result := Copy(ptr,1,len);

                 ptr := nil;

                 len := 0;

               end;

end;}

//==TStgStream===========================================================

constructor TStgStream.Create( const AName : String; AStorage : TStorage; AStream : IStream );

begin

       inherited Create;

       FStream := AStream;

       FStorage := AStorage;

       if AStorage<>nil then

       begin

               FPath := AStorage.FPath+AStorage.FName+'\';

               Inc(AStorage.FLockCount);

       end;

       FName := AName;

end; {TStgStream.Create}

//-------------------------------------------------------------

destructor TStgStream.Destroy;

begin

{        if FStream<>nil then

       begin

               FStream._Release;

               FStream := nil;

       end;}

       if FStorage<>nil then FStorage.Close;

       inherited Destroy;

end; {TStgStream.Destroy}

//-------------------------------------------------------------

function TStgStream.Read( var Buffer; Count : Longint ) : Longint;

begin

       Result := 0;

       if FStream<>nil then OleCheck( FStream.Read( @Buffer, Count, @Result ) );

end; {TStgStream.Read}

//-------------------------------------------------------------

function TStgStream.Write( const Buffer; Count : Longint ) : Longint;

begin

       Result := 0;

       if FStream<>nil then OleCheck( FStream.Write( @Buffer, Count, @Result ) );

end; {TStgStream.Write}

//-------------------------------------------------------------

function TStgStream.Seek( Offset : Longint; Origin : Word ) : Longint;

var        NewPos : LargeInt;

begin

       Result := 0;

       if FStream=nil then Exit;

       OleCheck( FStream.Seek( Offset, Origin, NewPos ) );

       Result := LongInt(NewPos);

end; {TStgStream.Seek}

//-------------------------------------------------------------

procedure TStgStream.SetSize( NewSize : Longint );

begin

       if FStream=nil then Exit;

       OleCheck( FStream.SetSize(NewSize) );

end; {TStgStream.SetSize}

//-------------------------------------------------------------

procedure TStgStream.SetName( Value : String );

begin

       if FName=Value then Exit;

       if FStorage<>nil then FStorage.RenameElement(FName,Value);

       FName := Value;

end; {TStgStream.SetName}

//==TStorage===========================================================

constructor TStorage.Create( const AName : String; AParent : TStorage; AStorage : IStorage );

begin

       inherited Create;

       FStorage := AStorage;

       FName := AName;

       FParent := AParent;

       if AParent<>nil then

       begin

               FPath := AParent.FPath+AParent.FName+'\';

               Inc(AParent.FLockCount);

       end;

end; {TStorage.Create}

//-------------------------------------------------------------

destructor TStorage.Destroy;

begin

{        if FStorage<>nil then

       begin

               FStorage._Release;

               FStorage := nil;

       end;}

       if FParent<>nil then FParent.Close;

       inherited Destroy;

end; {TStorage.Destroy}

//-------------------------------------------------------------

procedure TStorage.Close;

begin

       if FLockCount>0 then Dec(FLockCount) else Destroy;

end; {TStorage.Destroy}

//-------------------------------------------------------------

function TStorage.CreateStream( const AName : String; const Mode : DWord ) : TStgStream;

var        pw : PWideChar;

               rc : HResult;

               newStream : IStream;

begin

       Result := nil;

       if (FStorage=nil)or(AName='') then Exit;

       pw := StringToOleStr(AName);

       try

               rc := FStorage.CreateStream( pw, Mode, 0, 0, newStream );

               if rc<>S_OK then OleError(rc);

       finally

               SysFreeString(pw);

       end;

       if newStream=nil then Exit;

       Result := TStgStream.Create( AName, Self, newStream );

end; {TStorage.CreateStream}

//-------------------------------------------------------------

function TStorage.OpenStream( const AName : String; const Mode : DWord ) : TStgStream;

var        pw : PWideChar;

               rc : HResult;

               newStream : IStream;

begin

       Result := nil;

       if (FStorage=nil)or(AName='') then Exit;

       pw := StringToOleStr(AName);

       try

               rc := FStorage.OpenStream( pw, nil, Mode, 0, newStream );

               if rc<>S_OK then OleError(rc);

       finally

               SysFreeString(pw);

       end;

       if newStream=nil then Exit;

       Result := TStgStream.Create( AName, Self, newStream );

end; {TStorage.CreateStream}

//-------------------------------------------------------------

function TStorage.OpenCreateStream( const AName : String; const Mode : DWord ) : TStgStream;

var        pw : PWideChar;

               rc : HResult;

               newStream : IStream;

begin

       Result := nil;

       if (FStorage=nil)or(AName='') then Exit;

       pw := StringToOleStr(AName);

       try

               rc := FStorage.OpenStream( pw, nil, Mode and ($ffffffff xor STGM_CREATE xor STGM_CONVERT), 0, newStream );

               if rc=STG_E_FILENOTFOUND then rc := FStorage.CreateStream( pw, Mode, 0, 0, newStream );

               if rc<>S_OK then OleError(rc);

       finally

               SysFreeString(pw);

       end;

       if newStream=nil then Exit;

       Result := TStgStream.Create( AName, Self, newStream );

end; {TStorage.CreateStream}

//-------------------------------------------------------------

function TStorage.CreateStorage( const AName : String; const Mode : DWord ) : TStorage;

var        pw : PWideChar;

               rc : HResult;

               newStg : IStorage;

begin

       Result := nil;

       if AName='' then Exit;

       pw := StringToOleStr(AName);

       try

               rc := FStorage.CreateStorage( pw, Mode, 0, 0, newStg );

               if rc<>S_OK then OleError(rc);

       finally

               SysFreeString(pw);

       end;

       if newStg=nil then Exit;

       Result := TStorage.Create( AName, Self, newStg );

end; {TStorage.CreateStorage}

//-------------------------------------------------------------

function TStorage.OpenStorage( const AName : String; const Mode : DWord ) : TStorage;

var        pw : PWideChar;

               rc : HResult;

               newStg : IStorage;

begin

       Result := nil;

       if AName='' then Exit;

       pw := StringToOleStr(AName);

//  newStg := nil;

       rc := FStorage.OpenStorage( pw, nil, Mode, nil, 0, newStg );

       SysFreeString(pw);

       if rc<>S_OK then OleError(rc);

       if newStg=nil then Exit;

       Result := TStorage.Create( AName, Self, newStg );

end; {TStorage.OpenStorage}

//-------------------------------------------------------------

function TStorage.OpenCreateStorage( const AName : String; const Mode : DWord; var bCreate : Boolean ) : TStorage;

var        pw : PWideChar;

               rc : HResult;

               newStg : IStorage;

begin

       Result := nil;

       if AName='' then Exit;

       pw := StringToOleStr(AName);

       if bCreate then rc := FStorage.CreateStorage( pw, Mode, 0, 0, newStg )

       else

               begin

                       rc := FStorage.OpenStorage( pw, nil, Mode and ($ffffffff xor STGM_CREATE xor STGM_CONVERT), nil, 0, newStg );

                       if rc=STG_E_FILENOTFOUND then

                       begin

                               rc := FStorage.CreateStorage( pw, Mode, 0, 0, newStg );

                               bCreate := True;

                       end;

               end;

       SysFreeString(pw);

       if rc<>S_OK then OleError(rc);

       if newStg=nil then Exit;

       Result := TStorage.Create( AName, Self, newStg );

end; {TStorage.CreateStorage}

//-------------------------------------------------------------

procedure TStorage.EnumElements( AStrings : TStringList ; dwTypeNeed:DWORD);

const        MaxElem = 100;

var        rc : HResult;

               n,i : LongInt;

               oEnum : IEnumSTATSTG;

               aElem : Array [0..MaxElem-1] of TSTATSTG;

   sName : String;

begin

       if AStrings=nil then Exit;

       rc := FStorage.EnumElements(0,nil,0,oEnum);

       if rc<>S_OK then OleCheck(rc);

       n := MaxElem;

//        try

               repeat

                       oEnum.Next(MaxElem,aElem,@n);

                       if n>0 then

                               for i := 0 to n-1 do with aElem[i] do

                               begin

                       if ( dwType and dwTypeNeed ) <> 0 then

                   begin

                                       WideCharToStrVar(pwcsName,sName);

                                               AStrings.AddObject(sName,Pointer(dwType));

                                               CoTaskMemFree(pwcsName);

                   end;

                               end;

               until n<>MaxElem;

//        finally

//                oEnum._Release;

//    oEnum := nil;

//        end;

end; {TStorage.EnumElements}

//-------------------------------------------------------------

procedure TStorage.RenameElement( const AOldName, ANewName : String );

var        wcOld,wcNew : PWideChar;

               rc : HResult;

begin

       if (AOldName='')or(ANewName='')or(AOldName=ANewName)  then Exit;

       wcOld := StringToOleStr(AOldName);

       wcNew := StringToOleStr(ANewName);

       try

               rc := FStorage.RenameElement(wcOld,wcNew);

       finally

               SysFreeString(wcOld);

               SysFreeString(wcNew);

       end;

       OleCheck(rc);

end; {TStorage.RenameElement}

//-------------------------------------------------------------

procedure TStorage.SetName( Value : String );

begin

       if FName=Value then Exit;

       if (FStorage<>nil)and(FParent<>nil) then FParent.RenameElement(FName,Value);

       FName := Value;

end; {TStorage.SetName}

//==TStgFile===========================================================

constructor TStgFile.Create( const AFileName : String; AStorage : IStorage );

begin

       inherited Create('',nil,AStorage);

       if AFileName='' then Exit;

       FFileName := ExpandFileName(AFileName);

       FPath := FFileName+':';

end; {TStgFile.Create}

//-------------------------------------------------------------

class function TStgFile.CreateFile( const AFileName : String; const Mode : DWord ) : TStgFile;

var        pw : PWideChar;

               newStg : IStorage;

begin

       Result := nil;

       if AFileName='' then Exit;

       pw := StringToOleStr(AFileName);

       try

               newStg := nil;

               OleCheck( StgCreateDocFile(pw,Mode,0,newStg) );

       finally

               SysFreeString(pw);

       end;

       if newStg<>nil then Result := TStgFile.Create(AFileName,newStg);

end; {TStgFile.CreateFile}

//-------------------------------------------------------------

class function TStgFile.OpenFile( const AFileName : String; const Mode : DWord ) : TStgFile;

var        pw : PWideChar;

               newStg : IStorage;

begin

       Result := nil;

       if AFileName='' then Exit;

       pw := StringToOleStr(AFileName);

       newStg := nil;

       try

               OleCheck( StgOpenStorage(pw,nil,Mode,nil,0,newStg) );

       finally

               SysFreeString(pw);

       end;

       if newStg<>nil then Result := TStgFile.Create(AFileName,newStg);

end; {TStgFile.OpenFile}

//-------------------------------------------------------------

{function TStgFile.Clone( const Mode : DWord ) : TStgFile;

var        newStg : IStorage;

begin

       Result := nil;

       newStg := nil;

       if FStorage=nil then Exit;

       StgOpenStorage(nil,FStorage,Mode,nil,0,newStg);

       if newStg<>nil then Result := TStgFile.Create(Self.FFileName,newStg);

end; {TStgFile.Clone}

procedure TStorage.Commit( cflag:DWORD );

var

       rc:HRESULT;

begin

       if FStorage <> nil then

               rc := FStorage.Commit( cFlag );

   if rc <> S_OK then OleError( rc );

end;

end.