【问题标题】:How to get the full file name from a TextFile variable?如何从 TextFile 变量中获取完整的文件名?
【发布时间】:2018-03-13 09:03:04
【问题描述】:

以下代码写入名为 test.txt 的文件(在本例中,在当前目录中)

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

如何从F : TextFile 变量中提取完整的文件名?

【问题讨论】:

  • 这里好像有两个问题。 1. 如何从TextFile 对象中获取文件名? 2. 如何将相对文件名扩展为绝对路径?您希望我们回答哪个?每个帖子只问一个问题。
  • 这里有细微差别。打开文件时,相对文件名的扩展由TextFile 对象完成。但是,当您提出问题时,当前目录可能已经更改。我的建议是在调用AssignFile 之前执行扩展,并传递绝对文件名。然后不要忘记该文件名,这样您就不必希望TextFile 对象记住它。
  • @DavidHeffernan:你说得对,但我的目标是知道分配给TextFile 对象的完整文件名。正如你所说的“当前目录可能已经改变......”,所以我想知道 TextFile 对象是否在某处存储了完整的文件名。如果没有,我完全同意您的建议,我会在致电AssignFile 之前扩展路径
  • 似乎不太可能由 Delphi 对象存储完整的文件名。毕竟,它甚至都不会使用它。您需要获取文件句柄并从那里开始工作。
  • 为什么不使用 TFileStream?

标签: delphi delphi-5


【解决方案1】:

解决这个问题有两个步骤:

  1. 获取TextFile对象后面的文件句柄。
  2. 从该句柄中获取文件名。

对于第 1 步,您使用

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

第 2 步的过程在 MSDN 上进行了概述:Obtaining a File Name From a File Handle

【讨论】:

    【解决方案2】:

    由于 OP 似乎要求我最初理解的其他内容,因此我有以下答案:

    {$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;
    

    我目前使用 UNICODE 定义来确定 Delphi 是否已经有 GetFinalPathNameByHandle 的导入定义 - 如果我发现哪个版本实际实现了这个定义,它可能会被微调。

    另请注意,GetFinalPathNameByHandle 仅适用于 Windows Vista 及更高版本。如果尝试在以前的版本上运行,它将退回到简单地提取分配的文件名。如果您需要对 pre-Vista 的支持,您可以查看 David 链接到的页面,以获取适用于早期版本的版本。

    【讨论】:

    • 我在 Delphi 5 上试过你的代码,它在编译时引发了 2 个错误。 [Error] Unit1.pas(59): HIGH 不能应用于@Result[LOW(Result)] 上的长字符串[Error] Unit1.pas(59): Undeclared identifier: 'FILE_NAME_NORMALIZED'
    • @DavidHeffernan:是的,但如果这段代码可以帮助其他人,我认为它应该可以无错误地编译。这是我回复的唯一原因
    • 让我觉得奇怪的是,有这么多代码只是为了调用一个 API 函数。这并不难。而且我不认为我们真的需要更多糟糕的代码来导入 API 函数。所以是的,如果你要包含代码,它应该可以工作并且很好。
    • @ExDev:抱歉——我无法使用 D5 来测试编译。尝试更新版本 - 它应该消除了您注意到的两个问题。
    • 谢谢,它现在可以在 D5 上运行。我赞成你的回答
    【解决方案3】:

    你可以使用:

    TTextRec(F).Name
    

    从 TextFile 变量中提取 ASSIGN 文件名(上例中的“test.txt”)。

    如果“完整文件名”是指您希望它包括完整目录,您需要告诉我们您想要它用于哪个版本的 Delphi,因为更现代的版本在这方面有很多功能,早期版本没有。

    【讨论】:

    • SysUtils.ExpandFileName() 已经存在很久了。如果需要 UNC 格式,也可以使用 SysUtils.ExpandUNCFileName()
    • @LURD:由于我不确定这些功能实现的确切版本,所以我不想将它们作为选项提供,直到我知道(并且可以验证)它们在OP 正在使用的版本。
    • ExpandFileName 存在于所有版本的 Delphi 中。无论如何,您不应该觉得有必要迎合拥有旧版本的用户。工作不是帮助提问者,而是回答问题。如果提问者有一个古老的版本,那就是他们的问题。这两个函数都不是最近添加的。
    • @HeartWare:此时我使用的是旧的 Delphi 5,无论如何,我不想扩展路径,因为当前目录可能已经改变。我想知道TextFile 对象是否将完整文件名存储在某处
    • 如果您确定此答案不能解决问题,正如您在其他答案中所述,我认为您应该删除它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-11
    • 1970-01-01
    • 1970-01-01
    • 2010-09-30
    相关资源
    最近更新 更多