Conversion between absolute and relative paths in Delphi

可紊 提交于 2019-12-28 01:54:27

问题


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

For example:

  • 'Base' path is 'C:\Projects\Project1\'
  • Relative path is '..\Shared\somefile.pas'
  • Absolute path is 'C:\Projects\Shared\somefile.pas'

I am looking for something like this:

function AbsToRel(const AbsPath, BasePath: string): string;
// '..\Shared\somefile.pas' =
//   AbsToRel('C:\Projects\Shared\somefile.pas', 'C:\Projects\Project1\')  
function RelToAbs(const RelPath, BasePath: string): string;
// 'C:\Projects\Shared\somefile.pas' =
//   RelToAbs('..\Shared\somefile.pas', 'C:\Projects\Project1\')  

回答1:


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).




回答2:


To convert to the absolute you have :

ExpandFileName

To have the relative path you have :

ExtractRelativePath




回答3:


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.




回答4:


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.




回答5:


TPath.Combine(S1, S2);

Should be available since Delphi XE.




回答6:


An alternate solution for RelToAbs is simply:

ExpandFileName(IncludeTrailingPathDelimiter(BasePath) + RelPath)



回答7:


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;



回答8:


I am not too certain if this is still needed after 2+ years, but here is a way to get the Relative to Absolute (As for Absolute to Relative I would suggest philnext's ExtractRelativePath answer):

Unit: IOUtils

Parent: TPath

function GetFullPath(const BasePath: string): string;

It will return the full, absolute path for a given relative path. If the given path is already absolute, it will just return it as is.

Here is the link at Embarcadero: Get Full Path

And here is a link for Path Manipulation Routines




回答9:


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;


来源:https://stackoverflow.com/questions/5329472/conversion-between-absolute-and-relative-paths-in-delphi

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!