Conversion between absolute and relative paths in

2020-01-27 02:19发布

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\')  

标签: delphi path
9条回答
我欲成王,谁敢阻挡
2楼-- · 2020-01-27 02:50

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

查看更多
孤傲高冷的网名
3楼-- · 2020-01-27 02:51

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.

查看更多
The star\"
4楼-- · 2020-01-27 02:54
TPath.Combine(S1, S2);

Should be available since Delphi XE.

查看更多
Explosion°爆炸
5楼-- · 2020-01-27 02:57

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;
查看更多
成全新的幸福
6楼-- · 2020-01-27 02:58

An alternate solution for RelToAbs is simply:

ExpandFileName(IncludeTrailingPathDelimiter(BasePath) + RelPath)
查看更多
够拽才男人
7楼-- · 2020-01-27 03:02

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

查看更多
登录 后发表回答