Conversion between absolute and relative paths in Delphi

后端 未结 9 458
不思量自难忘°
不思量自难忘° 2020-11-30 01:18

Are there standard functions to perform absolute <--> relative path conversion in Delphi?

For example:

  • \'Base\' path is \'C:\\Projects\\Projec
相关标签:
9条回答
  • 2020-11-30 01:37

    For what it's worth, my codebase uses SysUtils.ExtractRelativePath in one direction and the following home-grown wrapper coming back:

    function ExpandFileNameRelBaseDir(const FileName, BaseDir: string): string;
    var
      Buffer: array [0..MAX_PATH-1] of Char;
    begin
      if PathIsRelative(PChar(FileName)) then begin
        Result := IncludeTrailingBackslash(BaseDir)+FileName;
      end else begin
        Result := FileName;
      end;
      if PathCanonicalize(@Buffer[0], PChar(Result)) then begin
        Result := Buffer;
      end;
    end;
    

    You'll need to use the ShLwApi unit for PathIsRelative and PathCanonicalize.

    The call to PathIsRelative means that the routine is robust to absolute paths being specified.

    So, SysUtils.ExtractRelativePath can be your AbsToRel only the parameters are reversed. And my ExpandFileNameRelBaseDir will serve as your RelToAbs.

    0 讨论(0)
  • 2020-11-30 01:44

    Another version of RelToAbs (compatible with all Delphi XE versions).

    uses
      ShLwApi;
    
        function RelPathToAbsPath(const ARelPath, ABasePath: string): string;
        var Buff:array[0..MAX_PATH] of Char;
        begin
          if PathCombine(Buff, PChar(IncludeTrailingPathDelimiter(ABasePath)), PChar(ARelPath)) = nil then
            Result := ''
          else Result:=Buff;
        end;
    
    0 讨论(0)
  • 2020-11-30 01:47

    An alternate solution for RelToAbs is simply:

    ExpandFileName(IncludeTrailingPathDelimiter(BasePath) + RelPath)
    
    0 讨论(0)
  • 2020-11-30 01:51

    I would use PathRelativePathTo as the first function and PathCanonicalize as the second. In the latter case, as argument you pass the string sum of the base path and the relative path.

    function PathRelativePathTo(pszPath: PChar; pszFrom: PChar; dwAttrFrom: DWORD;
      pszTo: PChar; dwAtrTo: DWORD): LongBool; stdcall; external 'shlwapi.dll' name 'PathRelativePathToW';
    
    function AbsToRel(const AbsPath, BasePath: string): string;
    var
      Path: array[0..MAX_PATH-1] of char;
    begin
      PathRelativePathTo(@Path[0], PChar(BasePath), FILE_ATTRIBUTE_DIRECTORY, PChar(AbsPath), 0);
      result := Path;
    end;
    
    function PathCanonicalize(lpszDst: PChar; lpszSrc: PChar): LongBool; stdcall;
      external 'shlwapi.dll' name 'PathCanonicalizeW';
    
    function RelToAbs(const RelPath, BasePath: string): string;
    var
      Dst: array[0..MAX_PATH-1] of char;
    begin
      PathCanonicalize(@Dst[0], PChar(IncludeTrailingBackslash(BasePath) + RelPath));
      result := Dst;
    end;
    
    
    procedure TForm4.FormCreate(Sender: TObject);
    begin
      ShowMessage(AbsToRel('C:\Users\Andreas Rejbrand\Desktop\file.txt', 'C:\Users\Andreas Rejbrand\Pictures'));
      ShowMessage(RelToAbs('..\Videos\movie.wma', 'C:\Users\Andreas Rejbrand\Desktop'));
    end;
    

    Of course, if you use a non-Unicode version of Delphi (that is, <= Delphi 2007), you need to use the Ansi functions (*A) instead of the Unicode functions (*W).

    0 讨论(0)
  • 2020-11-30 01:52

    Check if your solution will works with Relative Path To Full Path in case when you change current directory. This will works:

    function PathRelativeToFull(APath : string) : string;
    var
      xDir : string;
    begin
      xDir := GetCurrentDir;
      try
        SetCurrentDir('C:\Projects\Project1\');
        Result := ExpandFileName(APath);
      finally
        SetCurrentDir(xDir);
      end{try..finally};
    end;
    
    function PathFullToRelative(APath : string; ABaseDir : string = '') : string;
    begin
      if ABaseDir = '' then
        ABaseDir := 'C:\Projects\Project1\';
      Result := ExtractRelativePath(ABaseDir, APath);
    end;
    
    0 讨论(0)
  • 2020-11-30 01:53

    I just brewed this together:

    uses
      ShLwApi;
    
    function RelToAbs(const ARelPath, ABasePath: string): string;
    begin
      SetLength(Result, MAX_PATH);
      if PathCombine(@Result[1], PChar(IncludeTrailingPathDelimiter(ABasePath)), PChar(ARelPath)) = nil then
        Result := ''
      else
        SetLength(Result, StrLen(@Result[1]));
    end;
    

    Thanks to Andreas and David for calling my attention to the Shell Path Handling Functions.

    0 讨论(0)
提交回复
热议问题