Delphi Tpath.Combine ('c:', 'myfile.txt') excludes DirSeperator
So when I run
TPath.Combine('c:', 'myfile.txt');
in Delphi XE2 then I get "C: myfile.txt" instead. This is not what I expect, and it is not a valid path in windows. I would expect TPath.Combine to become a windows API call ( http://msdn.microsoft.com/en-us/library/fyy7a5kt%28v=vs.110%29.aspx ) or have the same behavior as API.
Is there something I am doing wrong? Can I "fix" TPath.Combine's behavior? Or do I have to search for all uses in my code and replace it with string concatenation with "\" in between?
source to share
I think the behavior is correct and how it was designed. There is a difference between C:myfile.txt
and C:\myfile.txt
. the windows documentation calls this explicitly:
If the filename begins with only a drive pointer, but not a backslash after the colon, it is interpreted as a relative path to the current directory on the drive with the specified letter. Note that the current directory may or may not be the root directory depending on which it was installed on during the last "change directory" operation on that drive. Examples of this format:
- "C: tmp.txt" refers to a file named "tmp.txt" in the current directory on drive C.
- "C: tempdir \ tmp.txt" refers to a file in a subdirectory of the current directory on drive C.
If the RTL function has TPath.Combine
added a separator after the drive pointer then you cannot use TPath.Combine
to create the path, eg "C:tmp.txt"
. So, if you want a directory separator, you need to supply it yourself:
TPath.Combine('c:\', 'myfile.txt');
Note that the framework.net framework method Path.Combine
, in which the Delphi RTL class is TPath
loosely modeled, behaves the same as the Delphi RTL equivalent.
Connected:
source to share
When concatenating folder names and folder files, it is always useful to specify the feeder name using the IncludeTrailingPathDelimiter method. This method will add a trailing separator to your path if it doesn't exist
TPath.Combine(IncludeTrailingPathDelimiter('c:'), 'myfile.txt');
source to share
The Path.Combine and CombinePath functions have problems with very long path names, in addition, when the path is not physically on disk (but, for example, in a zip file), then it also does not work. This implementation works for me:
function ExpandFileNameEx(const BasePath, RelativeFileName: string): string;
var
p:integer;
s,folder:string;
begin
{ Check if Relative file name is a fully qualified path: }
if (pos(':\', RelativeFileName) > 0) or (copy(RelativeFileName,1,2) = '\\') then
Result := RelativeFileName
{ Check if Relative file name is a root path assignment: }
else if copy(RelativeFileName,1,1) = '\' then
begin
Result := IncludeTrailingPathDelimiter(ExtractFileDrive(BasePath))
+ Copy(RelativeFileName,2,Length(RelativeFileName));
end else
begin
{ Check all sub paths in Relative file name: }
Result := BasePath;
s := RelativeFileName;
repeat
p := pos('\', s);
if p > 0 then
begin
folder := Copy(s,1,p-1);
Delete(s, 1,p);
end else
begin
folder := s;
s := '';
end;
if folder <> EmptyStr then
begin
if Folder = '..' then
Result := ExtractFileDir(Result)
else if Folder = '.' then
{ No action }
else
Result := IncludeTrailingPathDelimiter(Result) + Folder;
end;
until p = 0;
end;
end;
source to share