问题
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