Существуют ли стандартные функции для выполнения абсолютного < - - относительного преобразования пути в Delphi?
Например:
'C:\Projects\Project1\'
'..\Shared\somefile.pas'
'C:\Projects\Shared\somefile.pas'
Я ищу что-то вроде этого:
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\')
Я использовал бы PathRelativePathTo
в качестве первой функции и PathCanonicalize
как второй. В последнем случае в качестве аргумента вы передаете строчную сумму базового пути и относительного пути.
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;
Конечно, если вы используете версию Delphi, отличную от Unicode (то есть, <= Delphi 2007), вам нужно использовать функции Ansi (*A
) вместо функций Unicode (*W
).
Чтобы преобразовать в абсолют, вы имеете:
ExpandFileName
Чтобы иметь относительный путь:
ExtractRelativePath
Для того, что стоит, моя кодовая база использует SysUtils.ExtractRelativePath
в одном направлении, и следующая домашняя обертка возвращается:
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;
Вам понадобится блок ShLwApi
для PathIsRelative
и PathCanonicalize
.
Вызов PathIsRelative
означает, что подпрограмма является надежной для заданных абсолютных путей.
Итак, SysUtils.ExtractRelativePath
может быть вашим AbsToRel
, только параметры меняются на противоположные. И мой ExpandFileNameRelBaseDir
будет служить вашим RelToAbs
.
TWin32PathBuffer
является array[0..MAX_PATH-1] of char
?
Я просто сварил это вместе:
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;
Спасибо Андреасу и Дэвиду за то, что обратили мое внимание на Функции управления трассировкой оболочки.
TPath.Combine(S1, S2);
Должно быть доступно с Delphi XE.
Проверьте, будет ли ваше решение работать с Relative Path To Full Path в случае изменения текущего каталога. Это будет работать:
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;
Альтернативное решение для RelToAbs
просто:
ExpandFileName(IncludeTrailingPathDelimiter(BasePath) + RelPath)
Другая версия RelToAbs (совместимая со всеми версиями Delphi XE).
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;
Я не слишком уверен, что это все еще необходимо после 2+ лет, но вот способ получить отношение к абсолютному (Что касается абсолютного относительного, я бы предложил philnext ExtractRelativePath
ответ):
Единица: IOUtils
Родитель: TPath
function GetFullPath(const BasePath: string): string;
Он вернет полный, абсолютный путь для данного относительного пути. Если данный путь уже является абсолютным, он просто вернет его как есть.
Вот ссылка на Embarcadero: Получить полный путь
И вот ссылка для Процедуры манипулирования трафиком
C:\Projects\Shared\somefile.pas
-..
обозначает папку, которая в свою очередь удаляет `Project1` из базового (или корневого) пути.