Fabrizio
Fabrizio

Reputation: 8053

How to get the full file name from a TextFile variable?

The following code writes to a file named test.txt (In this case, in the current directory)

var
    F : TextFile;
begin
    AssignFile(F, 'test.txt');
    try
        Rewrite(F);
        //...
    finally
        CloseFile(F);
    end;
end;

How can I extract the full file name from the F : TextFile variable?

Upvotes: 1

Views: 2501

Answers (3)

HeartWare
HeartWare

Reputation: 8261

Since it seems like the OP asked for something else that I understood initially, I have the following answer instead:

{$J+}

USES Windows;

{$IFDEF UNICODE }
FUNCTION FileHandleToFileName(Handle : THandle) : STRING;
  BEGIN
    SetLength(Result,MAX_PATH+1);
    TRY
      SetLength(Result,GetFinalPathNameByHandle(Handle,@Result[LOW(Result)],LENGTH(Result),FILE_NAME_NORMALIZED))
    EXCEPT
      ON E:EExternalException DO SetLength(Result,0) ELSE RAISE
    END;
    IF COPY(Result,1,4)='\\?\' THEN DELETE(Result,1,4)
  END;
{$ELSE }
CONST FILE_NAME_NORMALIZED = $00000000;

FUNCTION GetFinalPathNameByHandleUndefined(hFile : THandle ; lpszFilePath : PChar ; cchFilePath,dwFlags : DWORD) : DWORD; stdcall;
  BEGIN
    StrPCopy(lpszFilePath,'');
    Result:=0
  END;

FUNCTION FileHandleToFileName(Handle : THandle) : STRING;
  TYPE
    TGetFinalPathNameByHandle   = FUNCTION(hFile : THandle ; lpszFilePath : PChar ; cchFilePath,dwFlags : DWORD) : DWORD; stdcall;

  CONST
    GetFinalPathNameByHandle    : TGetFinalPathNameByHandle = NIL;

  VAR
    Err                         : Cardinal;

  BEGIN
    IF NOT Assigned(GetFinalPathNameByHandle) THEN BEGIN
      GetFinalPathNameByHandle:=GetProcAddress(GetModuleHandle('kernel32'),'GetFinalPathNameByHandleA');
      IF NOT Assigned(GetFinalPathNameByHandle) THEN GetFinalPathNameByHandle:=GetFinalPathNameByHandleUndefined
    END;
    SetLength(Result,MAX_PATH+1);
    SetLength(Result,GetFinalPathNameByHandle(Handle,@Result[1],LENGTH(Result),FILE_NAME_NORMALIZED));
    IF COPY(Result,1,4)='\\?\' THEN DELETE(Result,1,4)
  END;
{$ENDIF }

FUNCTION FileNameOf(VAR TXT : TextFile) : STRING;
  VAR
    Handle      : THandle;

  BEGIN
    Handle:=TTextRec(TXT).Handle;
    Result:=FileHandleToFileName(Handle);
    IF Result='' THEN Result:=StrPas(TTextRec(TXT).Name)
  END;

I currently use UNICODE define to determine if Delphi already has an import definition for GetFinalPathNameByHandle - it can probably be fine tuned, if I find out which version actually implements this define.

Also note, that GetFinalPathNameByHandle is only valid for Windows Vista and on. If attempted to run on previous versions, it will fall back to simply extracting the file name that was ASSIGN'ed. If you need support for pre-Vista, you can look at the page that David linked to in order to get a version that should work on earlier versions.

Upvotes: 2

David Heffernan
David Heffernan

Reputation: 613442

There are two steps to solving this:

  1. Obtain the file handle behind the TextFile object.
  2. Get the file name from that handle.

For step 1 you use

var
  FileHandle: THandle;
....
FileHandle := TTextRec(F).Handle;

For step 2 the process is outlined on MSDN: Obtaining a File Name From a File Handle.

Upvotes: 2

HeartWare
HeartWare

Reputation: 8261

You can use:

TTextRec(F).Name

to extract the ASSIGN'ed file name ('test.txt' in the above example) from a TextFile variable.

If by "full file name" you mean you want it including full directory, you'll need to tell us which version of Delphi you want it for, as the more modern ones have a lot of functions in this area that the earlier versions don't.

Upvotes: 0

Related Questions