File

File

Remove all files and subdirectories
Write / Read array of records into a file
Read data from a file
Set a file's date and time
Import a large comma delimited file
Set compiled time in the aboutbox
CopyFile Function / Procedure
Reading Binary File
TOutline component read from file
Fixed field data input
Opening file for read only
File of type TList
Reading long strings from a file
GetFileSize
File Sharing question
Ascii code for eof
Iterating thru subdirectories
TMemoryStream
Saving a TTreeView's contents
A file of mulptiple records
Append Two Binary Files
Coping of the files
End Of File
File splitting and rejoining
How to match file date / time stamps
Copying files
Recursively removing files and subdirectories
Reading and writing data to/from files
Getting files date/time stamp
Storing TColor
Slow disk to diskette copy and back
How can I rename a directory
Save 500 chars from array into a file


Remove all files and subdirectories

Question


Has anyone run across a function that will recursively remove files and

directories given a starting subdirectory path. Failing that I would

settle for a simple RemoveDirectory function that will just remove a

given directory.



Answer


A:

This doesn't check for attributes being set, which might preclude deletion

of a file. Put a {$I-} {$I+} pair around the functions that cause the problem.



procedure removeTree (DirName: string);

var

   FileSearch:  SearchRec;

begin

   { first, go through and delete all the directories }

   chDir (DirName);

   FindFirst ('*.*', Directory, FileSearch);

   while (DosError = 0) do begin

      if (FileSearch.name <> '.') AND (FileSearch.name <> '..') AND

         ( (FileSearch.attr AND Directory) <> 0)

      then begin

         if DirName[length(DirName)] = '\' then

            removeTree (DirName+FileSearch.Name)

         else

            removeTree (DirName+'\'+FileSearch.Name);

         ChDir (DirName);

      end;

      FindNext (FileSearch)

   end;



   { then, go through and delete all the files }

   FindFirst ('*.*', AnyFile, FileSearch);

   while (DosError = 0) do begin

      if (FileSearch.name <> '.') AND (FileSearch.name <> '..') then

         Remove (workdir);

      end;

      FindNext (FileSearch)

   end;

   rmDir (DirName)

end;




Write / Read array of records into a file

Question


I need to save a array of record variable. Which is the best way to do it?

It's possible read the file with data-aware component?

Answer


A:

It's not very Delphi-like (but then, neither are Pascal records really),

but you can read and write records to and from a file using the standard

Pascal file manipulation procedures like so:



type

  TMyRec = record ;

    Field1 : integer ;

    Field2 : string ;

  end ;



  TMyRecArray = array [0..9] of TMyRec ;



var

  MyArray : TMyRecArray ;

  MyRec : TMyRec ;

  RecFile : file of TMyRec ;



begin



  {...some code that intializes MyArray goes here...}



  AssignFile( RecFile, 'MYREC.FIL' ) ;

  ReWrite( RecFile ) ;

  for i := 0 to 9 do

  begin

    Write( RecFile, MyRec[i] ) ;

  end ;

  CloseFile( RecFile ) ;



You can also use Read() to get a record from such a file, and Seek() to

move to a particular record in the file (starting with 0).  For more

details on these have a look at "I/O Routines" in the Delphi on-line

help.



If you want to do this with the Data Aware components, you'll have to

construct a database where the database "records" reflect the structure

of your Pascal records, then provide translation routines to get the

data from one to the other.  I'm not aware of any way to do this

directly, but it could certainly be encapsulated in a component.


Read data from a file

Question


How can I read data from a file being created by another program?

We have a program that collects data and constantly appends to a

daily file (ASCII text file). Even though the file has data in it, the file's

size is 0 until the program that is writing to it closes it. I need to read

records from this file as they are appended. I try reading from the file with

a Delphi program (see code below), it refuses to read any data from the file

until the other process closes it and the file size is updated.



procedure TestRead(FileName: String);

var

    AMAFile: File;

    BlockBuffer: Pointer;

    Result: Integer;

 begin

    BlockBuffer :=3D AllocMem(BlockSize);

    AssignFile(AMAFile, FileName);

    FileMode :=3D 0;

    try

       Reset(AMAFile, BlockSize);

    except

       MessageDlg('Unable to access ' + FileName, mtError, [mbOK], 0);

    end;

    BlockRead(AMAFile, BlockBuffer^, 1, Result);

    if(Result < 1) then

       MessageDlg('Unable to read first record from ' + FileName, mtError,

                   [mbOK], 0)

    else

       MessageDlg('Successfully read first record from ' + FileName,

                   mtInformation, [mbOK], 0);

    CloseFile(AMAFile);

    FreeMem(BlockBuffer, BlockSize);

 end;

Answer


A:

There is a procedure Flush that works with open text files.



     flush(f);



The manual is not clear on whether Flush commits the file to disk. If it

doesn't there would be data in other temporary buffers. As an extra measure

of safety I normally follow it with a call to dos. This call may not be needed

but, just in case.



A possible example follows:



Uses

     Sysutils;

var

     F    : text;             { this is your text file }

Procedure TextFlush(F : Text);

var

     fhandle   : word;

begin

   Flush(F);

   fhandle := ttextrec(F).Handle;       { get the msdos handle }

     asm

          mov  ax, $6800

          mov  bx, handle

          call DOS3CALL

          end;

   end;



If the file is a block file skip the flush step and use tfilerec instead of

ttextrec.



A:

The Filemode variable determins how the file is opened (By default in

exclusive mode).

Unfortunately it doesn't work on text files so you'ld have to use blockreads

and writes into a buffer and then convert the sections of the buffer to

strings if you want to handle it as a text file.



A:

Assign or AssignFile as it is now known cannot be used on a file that

is already open (I checked and this is documented). Now for one of my

famed shots in the dark - Why not use the API call to OpenFile

that's probably what you are using in C anyway.



A:

If it's a text file you first flush the text buffer with flush



     flush(f)



The rest applies to all files:

Commit the file using the dos commit function, available

since DOS 5.



     asm

          mov  ax, $6800                { commit file }

          mov  bx, ttextrec(f).handle   { get the handle of the file }

          call dos3call                 { this is the preferred way,  INT

$21 would work as well }

          end;





According to Microsoft documentation, this call also flushes the SMARTDRIVE

buffers.

The applicable MS language is as follows (MSDN10):



To flush the data held by the SMARTDRV.EXE version 4.0 buffer, you can

do one of the following:

 - Use the MS-DOS Commit File function (which writes changed data from

   the buffer). This is Interrupt 21h, function 68h.

 - Use the MS-DOS Disk Reset function (which writes changed data and

   invalidates/empties the cache). This is Interrupt 21h, function

   0Dh.


Set a file's date and time

Question


I have tried to set the date and time of a file I have created. I am

actually using the sample unit FMXUtils which is supplied with the

Delphi disks for the File Manager sample (in the documentation samples).

I found that the code in the unit was actually commented out and that

it did not actually work when I removed the comments. I've tried using

SetFTime, DOS calls (in inline assembly code) and other methods without

luck. No error is returned and the file's date and time are unaltered.

I don't want to have to call a shelled executable routine either.

Answer


A:

You've been in the correct direction for trying to use SetFTime. Below is

a few line of source that alter the date & time of a file:



var

  f: file;

begin

  Assign(f, DirInfo.Name);

  Reset(f);

  SetFTime(f, Time);

  Close(f);

end;


Import a large comma delimited file

Question


I have a large comma delimited file (average 500K) with variable length

fields (although the field types are standard) that I want to import into a

Paradox Table for quicker access.

The strings are in quotes, the numbers are not. However two problems I can

see, #1: If the field is blank there is nothing between the commas, #2:

Three of the character fields are a length of 500 characters.

Answer


A:

Here's two functions that I use will nearly all of my projects.

To use the routine is easy, eg:



var s: String; f: TextFile;

AssignFile(f, 'D:\INPUT.TXT);

Reset(f);

while not EOF(f) do

  begin

   ReadLn(s, f);

   ShowMessage(GetField(s, 1));  {The first field}

   ShowMessage(GetField(s, 6));  {The sixth field}

   ShowMessage(GetField(s, 25)); {will return '' if no 25 column...}

  end;

CloseFile(f);



{ ==== This function will return a field from a delimited string. ==== }

function GetField(InpString: String; fieldpos: Integer): String;

var

  c: Char;

  curpos, i: Integer;

begin

  curpos := 1;

  for i := 1 to fieldpos do

    begin

     result := ''; if curpos > Length(InpString) then Break;

     repeat

       c := InpString[curpos]; Inc(curpos, 1);

       if (c = '"') or (c = #13) or (c = #10) then c := ' ';

       if c <> ',' then result := result + c;

       until (c = ',') or (curpos > Length(InpString))

    end;

  if (curpos > Length(InpString)) and (i < fieldpos) then result := '';

  result := Trim(result);

end;



{ ==== This function will trim a string removing spaces etc. ==== }

function Trim(inp_str: String): String;

var

  i: Integer;

begin

  for i := 1 to Length(inp_str) do if inp_str[i] <> ' ' then Break;

  if i > 1 then Delete(inp_str, 1, i - 1);

  for i := Length(inp_str) downto 1 do if inp_str[i] <> ' ' then Break;

  if i < Length(inp_str) then Delete(inp_str, i + 1, Length(inp_str));

  result := inp_str;

  if result = ' ' then result := '';

end;


Set compiled time in the aboutbox

Question


How do you set the  compiled time in the aboutbox, so when you select

About, you know when was that app compiled.

Answer


A:

I am assuming that the problem is getting the complied time ?



Var

  F : Integer;

  S : String;

Begin

  F:=FileOpen(ExpandFileName(Application.ExeName), 0);

  S:=TimeToStr(FileDateToDateTime(FileGetDate(F)));

  FileClose(F);

End;



Look up DateTime... in the OnLine Help. There's probably a better way

without using FileOpen.



You might also consider using the File Time as a version number, so a

time of 6:02 is version 6.02, and set the time yourself, using something

like Touch.


CopyFile Function / Procedure

Question


SetFTime and GetFTime use the DOS interrupt $21 though. I'd prefer to use

some Windows API stuff myself, but I couldn't find reference to any similar

functions in the API.

Answer


A:

The unit which contains this code must have "LZExpand" in its "uses" clause

(without the quotes, of course).



"var" declarations:

  SourceHandle, DestHandle: Integer;

  SName,DName: String;



SName and DName are fully qualified source and destination file names.



In the body of the procedure:



  {set file handles}

  SourceHandle := FileOpen(SName,0);

  DestHandle := FileCreate(DName);



  {set buffer, perform copy, clear buffer}

  LZStart;

  CopyLZFile(SourceHandle,DestHandle);

  LZDone;



  {close files}

  FileClose(SourceHandle);

  FileClose(DestHandle);


Reading Binary File

Question


I am trying to read a binary file, 1 character at a time to match a

certain one. Does anyone have any ideas on how to do this.

Answer


A:

var

  f: File;

  c: Char;

begin

  AssignFile(f, 'this.bin');

  Reset(f, 1);

  BlockRead(f, c, sizeof(c));

  CloseFile(f);

end;



A:

function FindInFile( cFileName : string; cCh : char ) : boolean;

var fFile  : file;

    aBuf   : array[1..1024] of char;

    lFound : boolean;

    x,

    nRead  : integer;

begin

  Assign( fFile, cFileName );

  Reset( fFile, 1 );



  lFound := False;



  repeat

    BlockRead( fFile, aBuf, SizeOf( aBuf ), nRead );



    x := 1;

    while not lFound and ( x <= nRead ) do

      begin

        lFound := ( aBuf[ x ] = cCh )

        Inc( x )

      end;

  until ( nRead < SizeOf( aBuf ) ) or lFound;



  FindInFile := lFound

end;



A:

Have a look at the following code:



var

  f: file;

  c: Char;

begin

  AssignFile(f, 'c:\autoexec.bat);

  Reset(f, 1);                        <- Note: Record size = 1 byte normally!

  while not Eof(f) do

    begin

     BlockRead(f, c, SizeOf(c));

     {Now process c}

    end;

  CloseFile(f);

end;



To speed this procedure up, don't read 1 character at a time. Perhaps

it would be better to declare a PChar, say of size 200, and read in

a block of 200 bytes at a time. {eg BlockRead(f, p, 200);}

This though will take slightly more code than shown here...

(Still use a recordsize of 1, if you are not certain of blocksize)


TOutline component read from file

Question


I am having a bad time trying to use the outline component. I am trying to

write the data to a file and then read it back in.

If anybody has had some experience with this component I would appreciate

some tips.

Answer


A:

If you want to save a TOutline, then you might want to have a look to the

SaveToFile

and ReadFromFile methods. If you want to create your own file (to store the

associated

data along with your TOutline), then you should consider using a TStream

(or descendant -> TFileStream).



I had also problems to store a TOutline in a custom file. A simple way to 

achiev the goal is to create

a record like



TSaveNode=record

  Text: String

  Index: Longint;

  Parent: Longint;

  Data: Pointer

end;



This is all the information you need to save a TOutline. You can save it by 

iterating all the TOutlineNodes and write them to the Stream. To load the 

file read record by record and use the TOutline.AddChild method. The

trecord contains all the necessary information.


Fixed field data input

Question


I am trying to read in a text data file in fixed-field format, where variable

V1 is colums 1-3, V2 is colums 4-5, etc. What is the best method to import

this data in Delphi?

Answer


A:

     Here's the easiest way to do it, it might not be the best:



     var F : TextFile;

         S : String;



     AssignFile(F, 'FILENAME.TXT');

     Reset(F);

     while Not EOF(F)

     do    begin

              Readln(F, S);

              V1:= Copy(S,1,3);

              V2:= Copy(S,4,6);

              ...

           end;

     CloseFile(F);



     This is what I would normally do, but if the file is very large I

     would read it using blockread and scan the block afterwards. If you're

     thinking of using ODBC, I don't think it's worth it.


Opening file for read only

Question


I am working on an App that must allow multiple stations to open a

file a the same time.  Is there anyway to open a file for read

only,  and then should an update be needed,  lock the file so no

one else can do an update until the current operation is complete?



These files are created and read with the BlockRead and Blockwrite

commands if it's any help.

Answer


A:

Set the FileMode variable before opening or creating the file. You can use

the 'File Open Mode constants' to set this. Look at the help for 'Sysutils

unit'. About half way down the page you'll see 'File Open Mode constants'.

These work great with the FileMode variable. You should OR one of the

fmOpen... constants with one of the fmShare... constants to set the mode.



A:

Look-up the FileMode variable in help. If you set it to zero before opening

the file, the opening will be read-only. The default is read/write for

untyped files.



A:

  You might like to try setting the filemode after you assign the

file.  ie:

 

  AssignFile(F, FileName);

  FileMode := 0;  ( Set file access to read only }

  Reset(F);

  .

  .

  .

  CloseFile(F);


File of type TList

Question


I have a TList object which itself contains a TList object. I want to be able

to save the entire contents to a disk file.

Answer


A:

Ok, this is not as simple as it looks. However, some time ago with much

help from people on this list, I did this. Some source code for Toverheadmap

follows..



Note the ReadData and WriteData methods on the objects being written to

disk, and the SaveToFile and LoadFromFile methods on the TList itself. This

really should be a bit more generic, but I haven't had the time/inclination

to make it so as of yet. (Ie, the TList should be able to save/restore any

object with a readdata/writedata method.)





------------------------------------

unit Charactr;



interface



uses

    Graphics, StdCtrls, Classes, Sysutils, Winprocs, Ohmap, ohmstuff;



type

    TMapCharacterList = class(TList)

    private

    FMap:TOverHeadMap;

    public

    procedure RenderVisibleCharacters; virtual;

    procedure Savetofile(const filename:String);

    procedure Loadfromfile(const filename:String);

    procedure Clear;

    destructor Destroy; override;

    property MapDisp:TOverHeadMap read FMap write FMap;

    end;



    TFrameStore = class(TList)

    procedure WriteData(Writer:Twriter); virtual;

    procedure ReadData(Reader:TReader); virtual;

    procedure Clear;

    end;



    TMapCharacter = class(TPersistent)

    private

    FName:string;

    FMap:TOverHeadMap;

    FFrame:Integer;

    FFramebm,FFrameMask,FWorkBuf:TBitmap;

    FFrameStore,FMaskStore:TFrameStore;

    FXpos,FYpos,FZpos:Integer;

    FTransColor:TColor;

    FVisible,FFastMode,FIsClone,FRedrawBackground:Boolean;

    procedure SetFrame(num:Integer);

    function GetOnScreen:Boolean;

    procedure SetVisible(vis:Boolean);

    procedure MakeFrameMask(trColor: TColor);

    procedure MakeFrameMasks; {For switching to fast mode...}

    procedure ReplaceTransColor(trColor: TColor);

    procedure SetXPos(x:Integer);

    procedure SetYPos(y:Integer);

    procedure SetZPos(z:Integer);

    procedure SetFastMode(fast:Boolean);

    public

    constructor Create(ParentMap:TOverheadmap); virtual;

    destructor Destroy; override;

    property Name:string read FName write FName;

    property Fastmode:Boolean read FFastMode write SetFastMode;

    property FrameStore:TFrameStore read FFrameStore write FFramestore;

    property MaskStore:TFrameStore read FMaskStore write FMaskStore;

    property Frame:integer read FFrame write SetFrame;

    property Framebm:TBitmap read FFramebm;

    property FrameMask:TBitmap read FFrameMask;

    property TransColor:TColor read FTransColor write FTransColor;

    property Xpos:Integer read FXpos write SetXpos;

    property YPos:Integer read FYpos write SetYpos;

    property ZPos:Integer read FZpos write SetZpos;

    property Map:TOverHeadMap read FMap write FMap;

    property OnScreen:Boolean read GetOnScreen;

    property Visible:Boolean read FVisible write SetVisible;

    property IsClone:Boolean read FIsClone write FIsClone;

    property RedrawBackground:Boolean read FRedrawBackground write

FRedrawBackground;



    procedure Render; virtual;

    procedure RenderCharacter(mapcoords:Boolean;cxpos,cypos:Integer;mask,bm,

wb:TBitmap); virtual;



    procedure Clone(Source:TMapCharacter); virtual;



    procedure SetCharacterCoords(x,y,z:Integer); virtual;

    procedure WriteData(Writer:Twriter); virtual;

    procedure ReadData(Reader:TReader); virtual;

    end;



implementation



constructor TMapCharacter.Create(ParentMap:TOverheadmap);

begin

     inherited Create;

     FIsClone:=False;

     FFramebm:=TBitMap.create;

     FFrameMask:=TBitmap.Create;

     FWorkbuf:=TBitMap.Create;

     if Not(FIsClone) then

        FFrameStore:=TFrameStore.Create;



     FTransColor:=clBlack;

     FFastMode:=False;

     FMap:=ParentMap; end;



destructor TMapCharacter.Destroy;

var

a,b:Integer;

begin

     FFramemask.free;

     FFramebm.free;

     FWorkBuf.Free;

     if Not(FIsClone) then begin

        FFrameStore.Clear;

        FFrameStore.free;

     end;



     if (MaskStore<>nil) and Not(FIsClone) then begin

        MaskStore.Clear;

        MaskStore.Free;

     end;

     inherited Destroy; end;



{

 This procedure copies the relevant information from a character into itself

...

      Clones start out invisible, with zeroed map coordinates.

}



procedure TMapCharacter.Clone(Source:TMapCharacter);

begin

     FName:=Source.Name;

     FFastMode:=Source.FastMode;

     FFrameStore:=Source.FrameStore;

     FMaskStore:=Source.MaskStore;

     FTransColor:=Source.TransColor;

     FMap:=Source.Map;

     FVisible:=False;



     Frame:=Source.Frame; {Trigger frame retrieval.}



     FIsClone:=True; end;



procedure TMapCharacter.SetXPos(x:Integer);

begin

     Map.Redraw(xpos,ypos,zpos,-1);

     FXpos:=x;

     Render;

end;



procedure TMapCharacter.SetYPos(y:Integer);

begin

     Map.Redraw(xpos,ypos,zpos,-1);

     FYPos:=y;

     Render;

end;



procedure TMapCharacter.SetZPos(z:Integer);

begin

     Map.Redraw(xpos,ypos,zpos,-1);

     FZpos:=z;

     Render;

end;



procedure TMapCharacter.SetCharacterCoords(x,y,z:Integer);

begin

     Map.Redraw(xpos,ypos,zpos,-1);

     Fxpos:=x; Fypos:=y; Fzpos:=z;

     Render;

end;



procedure TMapCharacter.SetFrame(num:Integer);

begin

     if (num<=FFrameStore.count-1) and (num>-1) then begin

        FFrame:=num;

        FFramebm.Assign(TBitmap(FFrameStore.items[num]));

        if Ffastmode=false then begin

           FFrameMask.Width:=FFramebm.width;

           FFrameMask.Height:=FFramebm.height;

           FWorkBuf.Height:=FFramebm.height;

           FWorkBuf.Width:=FFramebm.width;

           makeframemask(TransColor);

           replacetranscolor(TransColor);

        end

        else begin

             FWorkBuf.Height:=FFramebm.height;

             FWorkBuf.Width:=FFramebm.width;

             FFrameMask.Assign(TBitmap(FMaskStore.items[num]));

        end;

     end;

end;



procedure TMapCharacter.MakeFrameMask(trColor: TColor);

var

testbm1,testbm2: TBitmap;

trColorInv: TColor;

begin

  testbm1 := TBitmap.Create;

  testbm1.width := 1;

  testbm1.height:=1;

  testbm2 := TBitmap.Create;

  testbm2.width := 1;

  testbm2.height:=1;

  testbm1.Canvas.Pixels[0,0]:=trColor;

  testbm2.Canvas.CopyMode:=cmSrcInvert;

  testbm2.Canvas.Draw(0,0,testbm1);

  trColorInv:=testbm2.Canvas.Pixels[0,0];

  testbm1.free;

  testbm2.free;

  with FFrameMask.Canvas do

    begin

    Brush.Color:= trColorInv;

    BrushCopy( Rect(0,0,FFrameMask.Width,FFrameMask.Height),FFramebm,

               Rect(0,0,FFramebm.Width,FFramebm.Height),trColor);

    CopyMode:=cmSrcInvert;

    Draw(0,0,FFramebm);

    end;

end;

procedure TMapCharacter.ReplaceTransColor(trColor: TColor);

begin

  with FFramebm.Canvas do

    begin

    CopyMode:=cmSrcCopy;

    Brush.Color:= clBlack;

    BrushCopy( Rect(0,0,FFramebm.Width,FFramebm.Height),FFramebm,

               Rect(0,0,FFramebm.Width,FFramebm.Height),trColor);

    end;

end;



function TMapCharacter.GetOnScreen:Boolean;

var

dispx,dispy:Integer;

begin

     dispx:=Map.width div map.tilexdim;

     dispy:=Map.height div map.tileydim;

     if (xpos>=Map.xpos) and (xpos<=map.xpos+dispx) and (ypos>=map.ypos) and

(ypos>=map.ypos+dispy) then

        result:=true; end;



procedure TMapCharacter.SetVisible(vis:Boolean);

begin

     if vis and OnScreen then Render;

     FVisible:=vis;

end;



procedure TMapCharacter.SetFastMode(fast:Boolean);

begin

     if fast<>FFastMode then begin

        if fast=true then begin

           FMaskStore:=TFrameStore.Create;

           MakeFrameMasks;

           FFastMode:=True;

           frame:=0;

        end

        else begin

            FMaskStore.Free;

            FFastMode:=False;

        end;

     end;

end;



procedure TMapCharacter.MakeFrameMasks;

var

a:Integer;

bm:TBitMap;

begin

     if FFrameStore.count>0 then begin

        for a:=0 to FFrameStore.Count-1 do begin

            Frame:=a;

            bm:=TBitMap.create;

            bm.Assign(FFrameMask);

            FMaskStore.add(bm);

        end;

     end;

end;



procedure TMapCharacter.Render;

var

x,y:Integer;

begin

     if visible and onscreen then

        RenderCharacter(true,xpos,ypos,FFramemask,FFramebm,FWorkbuf);

end;



procedure TMapCharacter.RenderCharacter(mapcoords:Boolean;cxpos,cypos:

Integer;mask,bm,wb:TBitmap);

var

x,y:Integer;

begin

     if map.ready then begin

        {

        If the user specifies it in mapcoords, we handle redrawing the tile

(s) first.

        if not, he does.

        }

        if mapcoords then begin

           if FRedrawBackground then

              Map.redraw(cxpos,cypos,FMap.zpos,-1);

           wb.Canvas.Draw(0,0,TMapIcon(FMap.Iconset[map.zoomlevel].items

[FMap.Map.Iconat(cxpos,cypos,Map.zpos)]).image);

           x:=(cxpos-Map.xpos)*FMap.tilexdim;

           y:=(cypos-Map.ypos)*FMap.tileydim;

        end

        else

            wb.Canvas.Copyrect(rect(0,0,FMap.tilexdim,FMap.tileydim),FMap.

Screenbuffer.canvas,rect(x,y,x+FMap.tilexdim,

            y+FMap.tileydim));



        with wb do begin

             Map.Canvas.CopyMode := cmSrcAnd;

             Map.Canvas.Draw(0,0,Mask);

             Map.Canvas.CopyMode := cmSrcPaint;

             Map.Canvas.Draw(0,0,bm);

             Map.Canvas.Copymode:=cmSrcCopy;

        end;

        Map.Canvas.CopyRect(Rect(x,y,x+FMap.tilexdim,y+FMap.tileydim),wb.

canvas,

        Rect(0,0,FMap.tilexdim,FMap.tileydim));

     end;

end;





procedure TMapCharacter.WriteData(Writer:TWriter);

begin

     with Writer do begin

          WriteListBegin;

          WriteString(FName);

          WriteBoolean(FFastMode);

          WriteInteger(TransColor);

          FFrameStore.WriteData(Writer);

          if FFastMode then

             FMaskStore.WriteData(Writer);

          WriteListEnd;

     end;

end;



procedure TMapCharacter.ReadData(Reader:TReader);

begin

     with Reader do begin

          ReadListBegin;

          Fname:=ReadString;

          FFastMode:=ReadBoolean;

          TransColor:=ReadInteger;

          FFrameStore.ReadData(Reader);

          if FFastMode then begin

             FMaskStore:=TFrameStore.Create;

             FMaskStore.ReadData(Reader);

          end;

          ReadListEnd;

     end;

end;



procedure TMapCharacterList.RenderVisibleCharacters;

var

a:Integer;

begin

     for a:=0 to count-1 do

         TMapCharacter(items[a]).render;

end;



procedure TMapCharacterList.clear;

var

obj:TObject;

begin

     {This routine deallocates all resources inside this here list}

     if self.count>0 then

     begin

          repeat

                obj:=self.items[0];

                obj.free;

                self.remove(self.items[0]);

          until self.count=0;

     end;

end;



destructor TMapCharacterList.Destroy;

var

a:Integer;

begin

     if count>0 then

        for a:=0 to count-1 do

            TObject(items[a]).free;

     inherited destroy; end;



procedure TMapCharacterList.loadfromfile(const filename:string);

var

   i:Integer;

   Reader:Treader;

   Stream:TFileStream;

   obj:TMapCharacter; begin

     stream:=TFileStream.create(filename,fmOpenRead);

     try

        reader:=TReader.create(stream,$ff);

        try

           with reader do begin

                try

                   ReadSignature;

                   if ReadInteger<>$6667 then

                      Raise EReadError.Create('Not a character list.');

                except

                      Raise EReadError.Create('Not a valid file.');

                end;

                ReadListBegin;

                while not EndofList do begin

                    obj:=TMapCharacter.create(FMap);

                    try

                       obj.ReadData(reader);

                    except

                          obj.free;

                          raise EReadError.Create('Error in character list

file.');

                    end;

                    self.add(obj);

                end;

                ReadListEnd;

           end;

        finally

               reader.free;

        end;

     finally

            stream.free;

     end;

end;



procedure TMapCharacterList.savetofile(const filename:String);

var

   Stream:TFileStream;

   Writer:TWriter;

   i:Integer;

   obj:TMapCharacter; begin

     stream:=TFileStream.create(filename,fmCreate or fmOpenWrite);

     try

        writer:=TWriter.create(stream,$ff);

        try

           with writer do begin

                WriteSignature;

                WriteInteger($6667);

                WriteListBegin;

                for i:=0 to self.count-1 do

                    TMapCharacter(self.items[i]).writedata(writer);

                WriteListEnd;

           end;

        finally

               writer.free;

        end;

     finally

            stream.free;

     end;

end;



procedure TFrameStore.WriteData(Writer:TWriter);

var

mstream:TMemoryStream;

a,size:Longint;

begin

     mstream:=TMemoryStream.Create;

     try

        with writer do begin

             WriteListBegin;

             WriteInteger(count);

             for a:=0 to count-1 do begin

                 TBitmap(items[a]).savetostream(mstream);

                 size:=mstream.size;

                 WriteInteger(size);

                 Write(mstream.memory^,size);

                 mstream.position:=0;

             end;

             WriteListEnd;

        end;

     finally

            Mstream.free;

     end;

end;



procedure TFrameStore.ReadData(Reader:TReader);

var

mstream:TMemoryStream;

a,listcount,size:Longint;

newframe:TBitMap;

begin

     mstream:=TMemoryStream.create;

     try

        with reader do begin

             ReadListBegin;

             Listcount:=ReadInteger;

             for a:=1 to listcount do begin

                 size:=ReadInteger;

                 mstream.setsize(size);

                 read(mstream.Memory^,size);

                 newframe:=TBitmap.create;

                 newframe.loadfromstream(mstream);

                 add(newframe);

             end;

             ReadListEnd;

        end;

     finally

            Mstream.free;

     end;

end;



procedure TFrameStore.clear;

var

Obj:TObject;

begin

     {This routine deallocates all resources inside this here list}

     if self.count>0 then

     begin

          repeat

                obj:=self.items[0];

                obj.free;

                self.remove(self.items[0]);

          until self.count=0;

     end;

end;



end.


Reading long strings from a file

Question


What's the easiest way to read in a long ASCII record directly into a PChar

or character array?  Can I use ReadLn for this?  All the examples in the

Delphi help use strings, but could I do something like this instead?

Answer


A:

You might want to consider using a stream (TFileStream,

TMemoryStream) to help you do the job. You'll have to find the CR/LF

pair yourself, but it would probably work fairly well -- something like this

(too lazy tonight for real code)



Start := Stream.Position;

End := Start;

Repeat

  Stream.Read(Buffer^, 1024);

  CRPos := FindCR(Buffer^);   { Where FindCR returns 0..1023 for CR,

                                                      1024 if not found}

  Inc(End, CRPos);

Until CRPos < 1024;

GetMem(MyPChar, End - Start);  { May be +-1 here -- again, lazy me! }

Stream.Seek(Start);

Stream.Read(MyPChar^, End - Start)



Then set the CR at the end of MyPChar to 0, and Seek to End + 1 or so

(to skip the LF).


GetFileSize

Question


Like everyone else (I suppose) I had patched around the lack

of a GetFileSize function and botched one together using

AssignFile, Reset, FileSize & CloseFile.

This merry morning I find that it doesn't work for files which

have the "Read only" attribute set.

I guess I could further botch it to work using FileGetAttr and

FileSetAttr, but I can't believe that there's nothing in the

Windows API.

Failing that, has anybody else written a nice clean GetFileSize

function that works properly for any file.   I'd prefer it to

work on an unopened file, or failing that on a File Handle, but

not from a "File Variable".

I don't want much, just the size in bytes.

Answer


A:

Here's a bit of code I use to determine info about a group of files:



var

  Fhnd2 : File ;

  sPath : String;

  tpath : string;

  SearchRec: TSearchRec;

  tempsearch : string;

  tempfiles : Integer;

  tempbytes : LongInt;

  wBytes : Word;

  sTemp : String ;

  iLen : Integer ;

  szString: Array[0..128] Of Char;

  ec : integer;



BEGIN



  {* Fetch System Directory *}

  MailManLogS('MailMan Begin');

  sTemp := ParamStr(0) ;

  iLen := Length(sTemp) ;

  WHILE sTemp[iLen] <> '\' DO

    DEC (iLen) ;

  StrPCopy(szString, sTemp) ;

  szString[iLen] := #0 ;

  SysDir := StrPas(szString) ;



  tempbytes := 0;

  tempfiles := 0;

  Files2bProc := 0;

  Bytes2bProc := 0;

  MailManLogS('Calculate Files To Be Processed');

  {* Find out how many files and bytes are to be processed *}

  tempsearch := SysDir + 'spool\witchcrf\d\*.*'  ;

  ec := FindFirst(tempsearch, faSysFile, SearchRec);

  While ec = 0 do

    begin

      if ((SearchRec.Name <> '.') and (SearchRec.Name <> '..')) then

        begin

          tempfiles := tempfiles + 1;

---->     tempbytes := tempbytes + SearchRec.Size;       <------

          TotalInBytes.Text := IntToStr(tempbytes);

          TotalInFiles.Text := IntToStr(tempfiles);

          MailManLogS('File-' + SearchRec.Name + '     Size-' + IntToStr(SearchRec.Size));



        end;

      ec := FindNext(SearchRec);

    end;



    MailManLogS('Total Files = ' + IntToStr(tempfiles) + '        Bytes = ' + IntToStr(tempbytes));



end;





All the syntax may not be right,  I just cut and paste a section of

one of my programs to demonstrate how the FindFirst Function

works.  It returns info about file in SearchRec which should

contain any info you want about a file.  I think it's exactly what

your looking for as the file doesn't have to be open.



A:

I have cobbled together something using FindFirst.

It returns a record of type TSearchRec.  This record contains a

variable Size which is the file size in bytes.  It may not be pretty

but it works.



function GetFileSize(FileName: string): Longint;

var

   SearchRec: TSearchRec;

begin

   if FindFirst(FileName, faAnyFile, SearchRec) = 0 then

      Result:=SearchRec.Size

   else

      Result:=-1;       {return an error, this can be anything less

                                     than zero}

end;



A:

If you like, you can pick one of these two for a start. The first is

a hack that changes the file attributes temporarily to allow the

read. The second uses the Windows API, but doesn't do any error 

checking.





Function FileGetSize1(Filename : String) : LongInt;

var

  F : File;

  OldFileAttr : Integer;

begin

  if FileExists(Filename)

    then

      begin

        OldFileAttr := FileGetAttr(Filename);

        FileSetAttr(Filename,OldFileAttr and (faReadOnly xor $FFFF));

        try

          AssignFile(F, Filename);

          Reset(F,1);

          Result := FileSize(F);

          CloseFile(F);

        finally

          FileSetAttr(Filename, OldFileAttr);

        end;

    end

  else

    Result := 0;

end;



Function FileGetSize2(Filename : String) : LongInt;

var

  FileHandle : Integer;

begin

  if FileExists(Filename)

    then

      begin

        FileName := FileName + chr(0);

        FileHandle := _lopen(@FileName[1], 0);

        Result := _llseek(FileHandle, 0, 2);

        _lclose(FileHandle);

      end

    else

      Result := 0;

end;



[Eric Nielsen, htrsoft@midwest.net]



A:

I didn't bother with AssignFile.



Function FileSizeInBytes(YourFile : String) : LongInt;

Var

  F : Integer;

Begin

  F:=FileOpen(YourFile,0);  { ReadOnly Mode }

  FilesizeInBytes := FileSeek(F,0,2);

  FileClose(F)

End;



Note: No error checking !!!


File Sharing question

Question


I have a robot-type application which runs unattended, and I am having

some filesharing problems:

The robot opens a text file for append, then adds a line to it, then

closes it. If the file is in use by someone else, even for read, Windows

puts up a message saying Sharing Violation, retry/cancel, and the robot

is then hung. This happens in win31 with vshare.386 and in win95.

I have tried flagging the files as Shareable (they are on a Novell

server), this doesnt help. I have looked at the filemodes available, and

none seem to help. How can I trap this error in my program, and handle it

myself?

Answer


A:

Have you tried a try ... except block yet?



I had a similar, but not the same, problem.



Code like this worked fine...



try

  {open file code goes here}

  ...

except

   {exception handling code goes here}

   {something like MessageDlg('Cannot open file', mtError, [mbOk], 0)

    would do nicely :) }

   ...

end;



A:

The Shareable netware attribute is used for EXE & COM files, and let

multiple users run one file.  This will not work for text files.



One method would be to check to see if the DOS "READ-ONLY" attribute is set.

Most DOS & Windows programs will set the flag after it opens a file to keep

everyone else out.  You can alternativly check for the NETWARE "READ-ONLY

file attribute.  This could be done with one of the NETWARE API components

that are floating around.  When your program finds one of these conditions

to be true, just have it wait a certain amount of time then check again.


Ascii code for eof

Question


What is the ascii code for the  marker for a text file

the same thing as the ascii code for  is #13.

Answer


The standard DOS EOF marker is control-Z, or ASCII character 26


Iterating thru subdirectories

Question


I know how to iterate through the files in a particular directory. But, how

do you iterate through the subdirectories of that directory?

Answer


A:

procedure TFormList.RecurseDir(PathInicial: string);

var

  SearchRec: TSearchRec;

  Result: integer;

  tmpName: string;

begin

     DirectoryListBox1.Directory:=PathInicial;

     Result:=FindFirst(PathInicial+'\*.*', faAnyFile, SearchRec);

     While Result = 0 do begin

          if ExtOk(SearchRec.Name) then

             { if directory... }

             if SearchRec.Attr and faDirectory > 0 then

                { recurse in... }

                RecurseDir(PathInicial+'\'+SearchRec.Name)

             else begin

                tmpName:=PathInicial+'\'+SearchRec.Name;

                tmpName:=Copy(tmpName,

                        Pos(PathOrigen,tmpName)+Length(PathOrigen),

                        Length(tmpName)-Length(PathOrigen));

                ListBox1.Items.Add(LowerCase(tmpName));

             end;

          Application.ProcessMessages;

          Result:=FindNext(SearchRec);

     end;

     DirectoryListBox1.Directory:=PathInicial;

end;


TMemoryStream

Question


Could anyone give any pointers to let me use

TMemoryStream to save data - mainly lines of strings.

Answer


A:

Think of memory stream as a file that is located in memory.  So the writes

are very similar to the write command for files.  (Actually it is closer to

the blockwrite command.)



To put a string the slow way you could do the following:



    for i := 1 to Length(s) do memstream.Write(s[i], 1);



That would write the string one character at a time.  Simple and easy to

understand, but a bit slow.  A faster way would be to do the following:



    memstream.Write(s[1], Length(s));



The two lines do the same thing, they append characters to the stream.  If

you have never done a seek on the stream, they just append to the end.



Now to handle the line feeds you have to add them yourself:



    memstream.Write(#13, 1);

    memstream.Write(#10, 1);



Or you could do some sneaky things like this:



    procedure StreamWriteStr(var ms: TMemoryStream; s: string);

    begin

        ms.Write(s[1], Length(s));

    end;



    procedure StreamWriteLnStr(var ms: TMemoryStream; s: string);

    begin

        StreamWriteStr(ms, s + #13#10);

    end;



Or you could create you own descendant class of TMemoryStream with a method

to write strings.


Saving a TTreeView's contents

Question


Is it possible to save the contents of a TTreeView and keep the

structure of the items an data in a file? I mean, is there a way to

save the items and data like (supose) SaveComponentData(MyTTreeView)

and then to load the items and data from the file (again supose)

LoadComponentData(MyTTreeView)?

Answer


It is possible:



MyTreeView.SaveToFile('Filename');



and later:



MyTreeView.LoadFromFile('Filename');



The problem: This method saves only the names of the items and the 

structure (the file is a textfile which reflects the structure). It 

doesn't save the ImageIndex property and so on. After "LoadFromFile"

you must restore the Images.


A file of mulptiple records

Question


I am writing an adventure game and need to store information

in a save game.  The game requires data from 3 different records

and one variable -



record1  = hotspot scene information(50 recs),

record2  = conversation information (60 recs),

record3  = hypertext information(50 recs)

variable = integer - # of scene currently on.



My problem is that I need to seek for a particular record of particular type

in the file ( I do not want to have to keep huge arrays of records in memory

). I know how to do this with a file containing records of only one record

type but have no clue how to combine all three records and one integer into

a single random access file.

Answer


I generally use a file with a header then just keep the header in memory and

use it to seek to the records I need.



Type

  TSaveHeader = Record

    scene    : Integer;

    hotspots : LongInt;

    talk     : LongInt;

    hype     : LongInt;

  End;



Var

  SaveHeader : TSaveHeader;



Procedure OpenSaveFile(fname : String);

Var

  f : File;

  i : Integer;

Begin

  AssignFile(f, fname);

  Reset(f, 1);

  BlockRead(f, SaveHeader, Sizeof(TSaveHeader));

  { get one set of records }

  Seek(f, SaveHeader.hotspots);

  For i := 1 To 50 Do

    BlockRead(f, somevar, sizeof_hotspotrec);

  { and so on }

  CloseFile(f);

End;



{ assuming the file is open }

Procedure GetHotspotRec(index : LongInt; Var hotspotrec : THotspot);

Var

  offset : LongInt;

Begin

  offset := SaveHeader.hotspots + index * Sizeof(THotSpot);

  Seek(f, offset);

  BlockRead(f, hotspotrec, Sizeof(THotspot));

End;


Append Two Binary Files

Question


I need to Append two Binary Files together how could I do that ?

Answer


The easiest way would be to open the first one, move to the end and copy the

second one.



Var

  f1, f2 : File;

  xfer   : Word;

  buf    : PChar;

Begin

  AssignFile(f1, name1);

  Reset(f1);

  Seek(f1, Filesize(f1));

  AssignFile(f2, name2);

  Reset(f2);

  GetMem(buf, 65000);

  Repeat

    BlockRead(f1, buf^, 65000, xfer);

    BlockWrite(f2, buf^, xfer);

  Until xfer < 65000;

  CloseFile(f1);

  CloseFile(f2);

End;


Coping of the files

Question


I have diffculties with coping the files. Delphi don't want to compile

LZCopy command.



this way it work very slow



pbBuf := PChar( LocalAlloc(LMEM_FIXED, 1) );



FileSeek(source,0,0);

FileSeek(dest,0,0);

repeat

    cbRead := Fileread(source, pbBuf, 1);

    FileWrite(dest, pbBuf, cbRead);

until (cbRead = 0);

Answer


A:

{  You must add LZExpand to your uses clause  ea. USES LZExpand; }

function CopyFile(SrcF,DestF : string) : boolean;

var

  SFile,

  DFile : integer;

  Res   : longint;

  Msg   : string;



begin

  SFile := FileOpen(SrcF,0);        { Open ReadOnly = 0, Write=1, Readwrite=2}

  DFile := FileCreate(DestF);

  Res := LZCopy(SFile,DFile);

  FileClose(SFile);

  FileClose(DFile);

  if Res < 0 then

  begin

    Msg := 'Unknown error';

    case Res of

      LZERROR_BADINHANDLE   : Msg := 'Invalid Source file handle';

      LZERROR_BADOUTHANDLE  : Msg := 'Invalid Destination file handle';

      LZERROR_BADVALUE      : Msg := 'Input parameter is out of range';

      LZERROR_GLOBALLOC     : Msg := 'Insufficient memory for the required buffers';

      LZERROR_GLOBLOCK      : Msg := 'Internal data structure handle invalid';

      LZERROR_READ          : Msg := 'Source file format is not valid';

      LZERROR_UNKNOWNALG    : Msg := 'The Source file was compressed with an unrecognized compression algorithm';

      LZERROR_WRITE         : Msg := 'There is insufficient space for the output file';

    end;

    MessageDlg(Msg,mtERROR,[mbOK],0);

    result := FALSE

  end else

    result := TRUE;

end;



A:

I'll bet it's slow! It's reading the file one character at a time... Try

allocating 8192 bytes and reading 8192 bytes at a time. That should speed

it up a bit...



A:

The simplest way to copy files is this:



                VAR

                         sI,dI:Longint;

                        sD,sS:TFilename;



                USES LZExpand;

                        ............

                  sI := FileOpen(sS,fmShareDenyWrite);

                 dI := FileCreate(sD);

                  { Copy file }

                   CopyLZFile(sI,dI);

                  {close files}

                 FileClose(sI);

                 FileClose(dI);


End Of File

Question


I have a typed file.  When using Eof() I do not get to the end of

file.  Now the only reason I know this is that I have another application

(not my own) that reads passed this point?

Answer


A:

I'm not sure that you are using eof() in the right context. eof()

simply CHECK's if you are at the end of "f" file.  It does not send you

anywhere.  Heres a sample of getting to the end of file.



  procedure gotoeof (f : file);

  { jumps to eof }



  begin

    seek (f, 0);   		{ goto start }

    seek (f, filesize(f));  	{ move ahead "x" number of bytes, in this

case the

				  size of the file! }

  end; {gotoeof}





A:

Eof() will only test for the end of file condition.  You need to use

Seek() or SeekEof() to set the file pointer to the end of file.


File splitting and rejoining

Question


Just wondering if anybody knows how to split a file (it will be compressed

via lha) across floppies and then successfully recombine the it later.

Answer


Not too hard, here's something that should do it:



   inf:   file;

   outf:  file;

   size:  longint;

   outsize: longint;

   amt:     word;

   amtRead: word;



   assignfile (inf, 'input file');

   reset (inf, 1);

   size := fileSize (inf);

   repeat

      showMessage (enter floppy in "A")  { or "B" or allow them to specify }

      assignFile (outf, 'A:output file');

      rewrite (outf, 1);

      outsize := diskFree (1);  { or 2 if it's the "B" drive }

      while (outsize > 0) and (size > 0) do begin

         amt := sizeof(buf);

         if amt > outsize then amt := outsize;

         blockRead (inf, buf, amt, amtRead);

         blockWrite (outf, buf, amtRead);

         dec (outSize, amtRead);

         dec (size, amtRead);

      end;

      closeFile (outf);

   until size <= 0;

   closeFile (inf);



This is OTTOMH, syntax hasn't been checked, etc.  You may want to add other

code to let the user specify the "A" or "B" drive, and/or a naming scheme so

that if disks get out of order it's trapped.



Re-assembling the files is similar: open outf on the hard disk, ask the user

for the first floppy, blockRead/blockWrite from the floppy to the hard disk,

then ask the user for the next floppy, etc. until all floppies are read.


How to match file date / time stamps

Question


How can I write a function that sets the date of one file equal to the date of another file?

Answer


{

A: No problem.  Just use the following function, which takes two strings

   representing full DOS path/file names.  The file who's date you

   wish to set is the second parameter, and the date you wish to set it to

   is given by the file in the first parameter.

}

procedure CopyFileDate(const Source, Dest: String);

var

  SourceHand, DestHand: word;

begin

  SourceHand := FileOpen(Source, fmOutput);       { open source file }

  DestHand := FileOpen(Dest, fmInput);            { open dest file }

  FileSetDate(DestHand, FileGetDate(SourceHand)); { get/set date }

  FileClose(SourceHand);                          { close source file } 

  FileClose(DestHand);                            { close dest file }

end;




Copying files

Question


How to copy files?

Answer


{

  Example #1 - uses a File stream

}

Procedure FileCopy( Const sourcefilename, targetfilename: String );

Var

  S, T: TFileStream;

Begin

  S := TFileStream.Create( sourcefilename, fmOpenRead );

  try

    T := TFileStream.Create( targetfilename,

                             fmOpenWrite or fmCreate );

    try

      T.CopyFrom(S, S.Size ) ;

    finally

      T.Free;

    end;

  finally

    S.Free;

  end;

End;



{

  Example #2 - uses memory blocks for read/write

}

procedure FileCopy(const FromFile, ToFile: string);

 var

  FromF, ToF: file;

  NumRead, NumWritten: Word;

  Buf: array[1..2048] of Char;

begin

  AssignFile(FromF, FromFile);

  Reset(FromF, 1);		{ Record size = 1 }

  AssignFile(ToF, ToFile);	{ Open output file }

  Rewrite(ToF, 1);		{ Record size = 1 }

  repeat

    BlockRead(FromF, Buf, SizeOf(Buf), NumRead);

    BlockWrite(ToF, Buf, NumRead, NumWritten);

  until (NumRead = 0) or (NumWritten <> NumRead);

  CloseFile(FromF);

  CloseFile(ToF);

end;





{

  Example #3 - uses LZCopy, which USES LZExpand

}

procedure CopyFile(FromFileName, ToFileName: string);

var

  FromFile, ToFile: File;

begin

  AssignFile(FromFile, FromFileName); { Assign FromFile to FromFileName }

  AssignFile(ToFile, ToFileName);     { Assign ToFile to ToFileName }

  Reset(FromFile);                    { Open file for input }

  try

    Rewrite(ToFile);                  { Create file for output }

    try

      { copy the file an if a negative value is returned }

      { raise an exception }

      if LZCopy(TFileRec(FromFile).Handle, TFileRec(ToFile).Handle) < 0

        then

        raise EInOutError.Create('Error using LZCopy')

    finally

      CloseFile(ToFile);  { Close ToFile }

    end;

  finally

    CloseFile(FromFile);  { Close FromFile }

  end;

end;




Recursively removing files and subdirectories

Question


Has anyone run across a function that will recursively remove files and

directories given a starting subdirectory path. 

Answer


{

  This is adapted from some code I wrote for Borland Pascal 5.5 under DOS (the

  original code didn't do rmDir, so you might want to experiment with where

  the directory pointer goes after the rmDir at the end of the function).  I

  suspect that the Delphi version is either identical or has a few changes in

  function name(s) (check the Delphi help for file management functions).

  This doesn't check for attributes being set, which might preclude deletion

  of a file.  (In Pascal 5.5, you'd put a {$I-} {$I+} pair around the

  functions that cause the problem; don't know if you do that in Delphi.)

}



procedure removeTree (DirName: string);

var

   FileSearch:  SearchRec;

begin

   { first, go through and delete all the directories }

   chDir (DirName);

   FindFirst ('*.*', Directory, FileSearch);

   while (DosError = 0) do begin

      if (FileSearch.name <> '.') AND (FileSearch.name <> '..') AND

         ( (FileSearch.attr AND Directory) <> 0)

      then begin

         if DirName[length(DirName)] = '\' then

            removeTree (DirName+FileSearch.Name)

         else

            removeTree (DirName+'\'+FileSearch.Name);

         ChDir (DirName);

      end;

      FindNext (FileSearch)

   end;



   { then, go through and delete all the files }

   FindFirst ('*.*', AnyFile, FileSearch);

   while (DosError = 0) do begin

      if (FileSearch.name <> '.') AND (FileSearch.name <> '..') then

         Remove (workdir);

      end;

      FindNext (FileSearch)

   end;

   rmDir (DirName)

end;




Reading and writing data to/from files

Question


How to read and write data from / to files?

Answer


{

  The following example shows how to write and read data to

  and from a file.  It is intended merely as a starting

  point for those that are struggling to get started with

  file related IO.  Please read the documentation on each

  object for more information.  Some very minimal exception

  handling is thrown in and by no means constitutes a

  robust solution



  In order to setup the program, place a TMemo component on

  a form with a Write captioned and a Read captioned button.

  Run the program, place some lines in the "memo", then

  press on Write.  Clear the "memo", and press on Read.

}

  procedure TForm1.BtnWriteClick(Sender: TObject);

  { by:  Michael Vincze

  }

  var

    FileStream: TFileStream;

    Writer    : TWriter;

    I         : Integer;

  begin

  FileStream := TFileStream.Create ('c:\delphi\projects\delta40\fileio\stream.txt',

    fmCreate or fmOpenWrite or fmShareDenyNone);

  Writer := TWriter.Create (FileStream, $ff);

  Writer.WriteListBegin;

  for I := 0 to Memo1.Lines.Count - 1 do Writer.WriteString (Memo1.Lines[I]);

  Writer.WriteListEnd;

  Writer.Destroy;

  FileStream.Destroy;

  end;



  procedure TForm1.BtnReadClick(Sender: TObject);

  { by:  Michael Vincze

  }

  var

    FileStream: TFileStream;

    Reader    : TReader;

  begin

  { try opening a non existent file

  }

  try

    FileStream := TFileStream.Create ('c:\delphi\projects\delta40\fileio\bogus.txt',

      fmOpenRead);

  except

    ; { no need to Destroy since the Create failed  }

    end;



  FileStream := TFileStream.Create ('c:\delphi\projects\delta40\fileio\stream.txt',

    fmOpenRead);

  Reader := TReader.Create (FileStream, $ff);

  Reader.ReadListBegin;

  Memo1.Lines.Clear;

  while not Reader.EndOfList do Memo1.Lines.Add (Reader.ReadString);

  Reader.ReadListEnd;

  Reader.Destroy;

  FileStream.Destroy;

  end;




Getting files date/time stamp

Question


How do I get a file's date and time stamp?

Answer


function GetFileDate(TheFileName: string): string;

var

  FHandle: integer;

begin

  FHandle := FileOpen(TheFileName, 0);

  try

    Result := DateTimeToStr(FileDateToDateTime(FileGetDate(FHandle)));

  finally

    FileClose(FHandle);

  end;

end;







DISCLAIMER: You have the right to use this technical information

subject to the terms of the No-Nonsense License Statement that

you received with the Borland product to which this information

pertains.




Storing TColor

Question


Simple question, but I can't find an example of storing a TColor in

either a database or an inifile, and I'm not sure how to deal with Hex.

Answer


Should be able to store it as IntToStr(thecolor);

No need to know hex.


Slow disk to diskette copy and back

Question


I wrote an "install.exe" in Delphi 2 that copies three files (total size,

1.09MB) from the installation diskette to the hard disk. The amazing problem

I have is that it takes fully ten minutes to copy the four files! I open

each file as a "file of byte" type, and read each byte then write each byte

to hard disk.

I can't figure out why its so slow.

Answer


A:

Instead of reading byte per byte, you should open the file with a record size of

64K or so, and read blocks. This will be much faster.

If you'd like to be real easy, there are components out there to copy files ....



Example of a copyfile routine :



 Function CopyFile(FromPath,ToPath : String) : integer;



 Var

   F1          : file;

   F2          : file;

   NumRead     : word;

   NumWritten  : word;

   Buf         : pointer;

   BufSize     : longint;

   Totalbytes  : longint;

   TotalRead   : longint;



 Begin

   Result := 0;

   Assignfile(f1,FromPath);

   Assignfile(F2,ToPath);

   reset(F1,1);

   TotalBytes := Filesize(F1);

   Rewrite(F2,1);

   BufSize := 16384;

   GetMem(buf,BufSize);

   TotalRead :=0;

   repeat

     BlockRead(F1, Buf^, BufSize, NumRead);

     inc(TotalRead,NumRead);

     BlockWrite(F2, Buf^, NumRead, NumWritten);

   until (NumRead = 0) or (NumWritten <> NumRead);

   if (NumWritten <> NumRead) then

      begin

        {error }

        result := -1;

      end   

   closefile(f1);

   Closefile(f2);

 End;



A:

If you have a file of byte, or just File, you should be using Blockread which

will allow a buffer size of 64Kb (ish). However, here is a quicker way. Use

Compress which I think comes with Delphi, otherwise is probably available on

Microsoft site, to create files like filename.ex_. This means that less info

needs transferring.

Below is some code to copy the files over. Even better, this will work on

your current files, since if the files are not compressed they simply get

copied !



function TInstallForm.UnCompress(src, dest: String; Var Error : LongInt):

Boolean;

var

  s, d: TOFStruct;

  fs, fd: Integer;

  fnSrc, fnDest: PChar;

begin

  src:=src + #0;

  dest:=dest + #0;

  fnSrc:=@src[1];   { Trick the Strings into being ASCIIZ }

  fnDest:=@dest[1];



  fs := LZOpenFile(fnSrc, s, OF_READ);    { Get file handles }

  fd := LZOpenFile(fnDest, d, OF_CREATE);



  Error:=LZCopy(fs, fd);           { Here's the magic API call }

  Result:=(Error > -1);



  LZClose( fs );    { Make sure to close 'em! }

  LZClose( fd );

end;



Procedure UnCompressError(Error : LongInt);

Begin

  Case Error Of

    LZERROR_BADINHANDLE : S:='The handle identifying the source file was not

    valid';

    LZERROR_BADOUTHANDLE: S:='The handle identifying the destination file was

    not valid';

    LZERROR_BADVALUE    : S:='The input parameter was out of the allowable

    range';

    LZERROR_GLOBALLOC   : S:='There is insufficient memory for the required

    buffers';

    LZERROR_GLOBLOCK    : S:='The handle identifying the internal data

    structures is invalid';

    LZERROR_READ        : S:='The source file format was not valid';

    LZERROR_UNKNOWNALG  : S:='The source file was compressed with an

    unrecognised compression algorithm';

    LZERROR_WRITE       : S:='There is insufficient space for the output file'

    Else

      S:='Unknown problem with Uncompress'

  End;

  MessageDlg(S, mtConfirmation,[mbOK],0);

  Close

End;



A:

function CopyFile( SrcName,DestName : string ): boolean;

	{ generic file copy routine; requires

		full path & name for source & destination }

var

  Buf: array[1..1024*4] of byte;   { this size can be adjusted.. by

declaring a pointer you can use GetMem to create a large buffer on the heap }

  TotalRead: longint;

  NumRead,

     NumWritten: word;

  TotalWritten: longint;

  FromFileSize: longint;

  FrF,ToF	: file;

  FileTime	: longint;

begin



  FGetTime(SrcName,FileTime);

  Assign(FrF,SrcName);

  Reset(FrF,1);

  FromFileSize := FileSize(FrF);



  Assign(ToF,DestName);

  Rewrite(ToF,1);

  TotalRead := 0;

  TotalWritten := 0;

  REPEAT

      BlockRead (FrF, Buf, SizeOf(Buf), NumRead);

      TotalRead := TotalRead + NumRead;



       BlockWrite(ToF, Buf, NumRead, NumWritten);

      TotalWritten := TotalWritten + NumWritten;

  UNTIL (NumRead = 0) OR (NumWritten <> NumRead);

  Close(FrF);

  Close(ToF);

  { returns true if these are equal, false if not equal }

  CopyFile := (TotalWritten = FromFileSize);

end;


How can I rename a directory

Question


Does anybody know how to rename a directory ?

Answer


The RenameFile function (SysUtils unit) works for directories as well as files.


Save 500 chars from array into a file

Question


I load an array of 500 chars at run time and I would like to save it to a file.



Answer


A:

The following code should get you started.



Type

TCharArray = Array[500] of Char;



Procedure WriteToFile(Var aArray : TCharArray; sFileName : String); {Note:

Declaring the array as a Var parameter causes a pointer to the array to be

passed, rather than the copying of the entire array onto the stack - you

may prefer to take the slight overhead for the safety provided by not

passing it as a Var parameter.}



Var

nArrayIndex : Word;

fFileHandle : TextFile;

Begin

AssignFile(fFileHandle, sFileName);

Rewrite(fFileHandle);



For nArrayIndex := 1 to 500 Do

Begin

Write(fFileHandle, aArray[nArrayIndex]); End;



CloseFile(fFileHandle);

End; {end Procedure, WriteToFile()}




Close    To Top
  • Prev Article-Programming:
  • Next Article-Programming:
  • Now: Tutorial for Web and Software Design > Programming > delphi > Programming Content
    Photoshop Tutorial
     

    Special Effect

      3D Effect
      Photoshop Articles
    Programming Tutorial
     

    C/C++ Tutorial

      Visual Basic
      C# Tutorial
    Database Tutorial
     

    MySQL Tutorial

      MS SQL Tutorial
      Oracle Tutorial
    Geek Tutorial
     

    Blogging Tutorial

      RSS Tutorial
      Podcasting Tutorial
    Graphic Design Tutorial
      Coreldraw Tutorial
      Illustrator Tutorial
      3D Tutorials
    Webmaster Articles
     

    Domain Service

      Web Hosting
      Site Promotion
    Java Tutorial/ Articles
     

    Java Servlets

      JavaEE Tutorial
     

    JavaBeans Tutorial

    XML Tutorial/ Articles
     

    XML Style

      AJAX Tutorial
      XML Mobile
    Flash Tutorial/ Articles
     

    Flash Video

      Action Script
      Flash Articles
    OS Tutorial/ Articles
      Linux Tutorial
      Symbian Tutorial
      MacOS Tutorial
    Personal Tech
      Hardware Tutorial
      Software Tutorial
      Online Auction