【问题标题】:Delphi Tpath.Combine('c:', 'myfile.txt') leaves out DirSeperatorDelphi Tpath.Combine('c:', 'myfile.txt') 省略了 DirSeperator
【发布时间】:2014-09-04 15:53:44
【问题描述】:

所以当我跑步时

TPath.Combine('c:', 'myfile.txt');

在 Delphi XE2 中,我得到 'C:myfile.txt' 作为回报。这不是我所期望的,它不是 Windows 中的有效路径。我希望 TPath.Combine 调用 Windows API (http://msdn.microsoft.com/en-us/library/fyy7a5kt%28v=vs.110%29.aspx) 或具有与 API 相同的行为。

我做错了什么吗?我可以“修复” TPath.Combine 的行为吗?还是我必须在我的代码中搜索所有用途并将其替换为字符串连接并在其间添加一个“\”?

【问题讨论】:

  • 小吹牛,.NET 不是 Windows API(而且 Delphi 与 .NET 不一样 ;))
  • Win32 API 函数为PathCombine()
  • 您链接到的 Path.Combine 的文档说它也会返回 c:myfile.txt:“如果 path1 不是驱动器引用(即“C:”或“D:”)并且不以 DirectorySeparatorChar、AltDirectorySeparatorChar 或 VolumeSeparatorChar 中定义的有效分隔符结尾,DirectorySeparatorChar 在连接之前附加到 path1。"
  • @hvd:不,你错了。请再次阅读规范。
  • @hvd 读取正确,当然你可以随时执行函数调用,看看它返回什么

标签: delphi path delphi-xe2


【解决方案1】:

我认为行为是正确的,并且符合设计。 C:myfile.txtC:\myfile.txt 之间存在差异。 Windows documentation 非常明确地指出了这一点:

如果文件名仅以磁盘指示符开头而不是 冒号后面的反斜杠,它被解释为一个相对路径 具有指定字母的驱动器上的当前目录。注意 当前目录可能是也可能不是根目录,具体取决于 在最近的“更改目录”期间设置的内容 该磁盘上的操作。这种格式的例子如下:

  • “C:tmp.txt”是指C盘当前目录下名为“tmp.txt”的文件。
  • “C:tempdir\tmp.txt”指的是驱动器 C 上当前目录的子目录中的文件。

如果 RTL 函数 TPath.Combine 在驱动器指示符后添加分隔符,那么您将无法使用 TPath.Combine 生成类似 "C:tmp.txt" 的路径。所以,如果你想要一个目录分隔符,你需要自己提供一个:

TPath.Combine('c:\', 'myfile.txt');

请注意,Delphi RTL 类 TPath 松散建模的 .net 框架方法 Path.Combine 的行为与 Delphi RTL 等效项相同。

相关:

【讨论】:

    【解决方案2】:

    在组合文件夹名称和文件夹文件时,最好通过 IncludeTrailingPathDelimiter 方法放置文件夹名称。如果没有,此方法将在您的路径中添加尾随分隔符

    TPath.Combine(IncludeTrailingPathDelimiter('c:'), 'myfile.txt');
    

    【讨论】:

    • TPath.Combine() 等函数的目的是为您处理斜线,因此您不必手动插入它们。
    • @RemyLebeau 好吧,系统无法为你处理这个问题,因为系统无法读懂你的想法,也无法知道你是否想要一个这里
    • 文档没有指定任何关于 TPath.Combine 以自动添加斜杠。
    • @SilverWarior 您错过了 Remy 试图提出的观点。他的观点是 TPath.Combine 的加注是为了避免您担心尾随斜杠。
    • 那么我会说它的设计是有缺陷的,因为你没有得到你所期望的结果。至于我的回答,这是针对这个特定问题的解决方法。
    【解决方案3】:

    Path.Combine 和 CombinePath 函数在路径名过长时存在问题,此外,当路径实际上不在驱动器上(但例如在 zip 文件中)时,它也不起作用。这个实现对我有用:

    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;
    

    【讨论】:

      【解决方案4】:

      这就是为什么你应该总是使用IncludeTrailingBackslash(或者IncludeTrailingPathDelimiter,如果你是一个受虐狂):

      • 之前TPath.Combine('c:', 'myfile.txt');
      • 之后IncludeTrailingBackslash('c:')+'myfile.txt';

      当他们设计their abstraction.时,它避免了其他人正在考虑的未知细微差别,或者他们不想处理的边缘情况,或者他们不想记录的怪癖。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-07-16
        • 2011-01-30
        • 1970-01-01
        • 2020-11-21
        • 1970-01-01
        • 1970-01-01
        • 2022-01-16
        • 2021-06-05
        相关资源
        最近更新 更多