我什么时候应该使用 NSURLCanonicalPathKey?

ken*_*nyc 5 url macos cocoa core-foundation appkit

在 macOS 10.12 中,NSURLCanonicalPathKey被添加到NSURL. 文档指出:

\n\n
\n

URL 的路径作为规范的绝对文件系统路径。

\n
\n\n

除此之外,我看到的唯一其他文档/信息来自Swift 论坛帖子,其中指出:

\n\n
\n

您可能想查看 .canonicalPathKey (NSURLCanonicalPathKey)。在 Apple 平台上,许多标准 UNIXy 路径都存在于 /private/ 中,并具有来自根目录的相应符号链接。所以/etc/实际上是/private/etc/。如果您不\xe2\x80\x99t 规范化路径,您可能会因此而陷入困境。

\n
\n\n

这对我来说似乎是一件大事,但令我惊讶的是它只在 10.12 中引入。我曾经只依赖NSURLPathKey.path书签数据来解析 URL,但从来没有遇到过问题

\n\n
    \n
  • 我现在应该在以前使用过的所有地方都使用规范路径\n标准路径值吗?

  • \n
  • 如果我将路径信息作为字符串存储在数据库中,我应该存储.pathor的值吗NSURLCanonicalPathKey

  • \n
  • 如果我将 转换NSURL为字符串表示形式以在需要文件路径的 C/C++ 库中使用,我应该使用规范路径表示形式吗?

  • \n
  • 如果您要向用户显示文件的路径,是否应该显示规范路径?

  • \n
  • 与和NSURLCanonicalPathKey相比如何,它们似乎做了相同的事情或相反的事情......(?)URLByStandardizingPathURLByResolvingSymlinksInPath

  • \n
\n\n

这是在 macOS 10.14 上,我只考虑指向文件或文件夹的 URL。我知道书签数据可能应该存储在数据库中而不是路径中。

\n

Tho*_*ann 5

这取决于您计划如何使用该路径:

\n
    \n
  • 如果您只想向用户显示路径,或者存储它以供以后使用 重新创建 URL [NSURL fileURLWithPath:],那么您可以继续使用收到的常规路径,因为通常您会因为用户将其提供给而获得路径以某种方式改变你,然后最好不要改变它。
  • \n
  • 当然,重新创建 URL 可以使用任一路径表示形式。但是,如果您从“/etc”创建一个 URL,并从“/private/etc”创建一个 URL,[NSURL isEqual:]则会出现false- 如果您不喜欢这样,则必须对它们进行规范化。
  • \n
  • 因此,如果您想注册路径以便稍后重新识别给您的相同路径,那么您应该将其规范化。
  • \n
  • 请记住,获取规范路径会增加大量的处理时间(很容易使其增加一倍)。这就是为什么在没有必要的情况下要避免使用它。
  • \n
\n

Unicode 标准化也可能很重要。例如,如果文件或文件夹使用预组合(NFC)字符,NSURL 方法会将它们转换为 NFD 字符串。OTOH,BSD/POSIX 函数不会这样做。因此,例如,如果您从 shell 命令获取路径,然后将它们与从 NSURL 获得的路径进行比较,则由于使用 NFC 和其他 NFD 字符,它们可能不会计算为相等。理想情况下,如果 NSURL 或 NSFileManager 涉及路径,那么您还应该首先通过 NSURL 传递 BSD 路径,以便最终获得具有相同组合格式的两种类型的路径。

\n

例子

\n

不涉及标准化的简单示例:

\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
输入URL按标准化路径NSURLCanonicalPathKey
/私人/var/var/私人/var
/var/var/私人/var
\n

Unicode 规范化

\n

以下示例使用准备好的 APFS 卷,其中包含带有字母“\xc3\xbc”的预组合和分解表示形式的文件名以及符号链接。您可以在此处下载磁盘映像文件

\n

目录布局如下:

\n
$ cd /Volumes/Canonical_Normalize_Test/\n$ ls -lR\ntotal 24\n-rw-r--r--  1 user  staff   19 Dec 29 19:27 decomposed_\xc3\xbc\n-rw-r--r--  1 user  staff   19 Dec 29 19:27 precomposed_\xc3\xbc\ndrwxr-xr-x  4 user  staff  128 Dec 29 19:36 symlink_target_dir\nlrwxr-xr-x  1 user  staff   18 Dec 29 19:36 symlink_to_dir -> symlink_target_dir\n-rwxr-xr-x@ 1 user  staff  763 Dec 15 16:28 unicode_composition_check.sh\n\n./symlink_target_dir:\ntotal 0\nlrwxr-xr-x  1 user  staff  17 Dec 29 19:36 decomposed_\xc3\xbc -> ../decomposed_\xc3\xbc\nlrwxr-xr-x  1 user  staff  17 Dec 29 19:36 precomposed_\xc3\xbc -> ../precomposed_\xc3\xbc\n
Run Code Online (Sandbox Code Playgroud)\n

文件“unicode_composition_check.sh”是一个脚本,用于创建两个“...\xc3\xbc”文件,一个使用 NFD 命名,另一个使用 NFC 命名(不幸的是,该脚本命名不正确)。

\n

输入是:

\n
/Volumes/Canonical_Normalize_Test/symlink_to_dir/precomposed_\\U00fc\n
Run Code Online (Sandbox Code Playgroud)\n

(即路径包含目录符号链接并使用实际文件的 unicode 组成,即目标文件名的“\xc3\xbc”是预先组成的。)

\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n
方法结果
文件系统表示/Volumes/Canonical_Normalize_Test/symlink_to_dir/precomposed_u\\U0308
URL按标准化路径/Volumes/Canonical_Normalize_Test/symlink_to_dir/precomposed_u\\U0308
NSURLCanonicalPathKey/Volumes/Canonical_Normalize_Test/symlink_target_dir/precomposed_u\\U0308
URLByResolvingSymlinksInPath/Volumes/Canonical_Normalize_Test/precomposed_u\\U0308
\n
\n

我们看到每种方法都会给出不同的结果:

\n
    \n
  1. 它们似乎都将路径标准化为 NFD,即“\xc3\xbc”在所有情况下都会被分解。对于常规的不区分大小写的卷来说,这是必要且正常的,因为文件名的查找是规范化不敏感的。但是:对于区分大小写的卷,不得更改其组成,虽然我没有对此进行测试,但我假设上述所有函数都将检测卷的区分大小写模式并相应地运行。

    \n
  2. \n
  3. NSURLCanonicalPathKey当我们想要稍后通过路径重新识别目标项时才给出所需的正确结果(与使用哪种 Unicode 组合以及路径是否包含指向目录的符号链接无关):它解析目录符号链接,但不解析最终符号链接那是在里面的symlink_target_dir。如果它确实解析了最终路径元素(就像URLByResolvingSymlinksInPath这样做),您将无法定位符号链接文件。

    \n
  4. \n
  5. NSString\'sfileSystemRepresentation不会更改路径(但对其进行规范化),而 NSURL\'sURLByStandardizingPath在某些情况下会更改路径(例如,通过从某些根文件夹中删除“/private”)。

    \n
  6. \n
  7. NSURLCanonicalPathKey会根据实际的磁盘路径修复大小写。例如,从“/applications”创建的 URL 不会被任何其他函数转换为实际的“/Applications”路径。

    \n
  8. \n
\n

结论

\n

如果您稍后需要重新识别路径,无论使用哪种表示形式(规范化、指向目录的符号链接),NSURLCanonicalPathKey如果您需要保留实际项目(即使它是符号链接),请使用其中之一,或者使用URLByResolvingSymlinksInPath始终识别给您的任何符号链接的目标。

\n

但请注意(请参阅第一个示例),如果您使用URLByResolvingSymlinksInPath,“/private/var/tmp”等将变成“/var/tmp”等,这是不常见的,因为它仍然包含符号链接(即“/变种”)。

\n

另请记住,除非您获得规范路径,否则情况可能不正确。为了弥补这一点,比较路径要求您首先检查路径是否位于不区分大小写的卷上,以便您使用正确的比较选项(并且,作为一个额外的复杂性,只需将路径与“不区分大小写”的卷进行比较)对于 HFS+ 卷上的某些罕见脚本,选项可能不正确,因为它们使用较旧的 Unicode 标准,该标准具有与当前 macOS 版本使用的其他规则不同的规则。

\n

最后,如果您只想查看两个路径是否指向同一个文件,那么使用不依赖路径的其他方法会更安全。看到这个答案。如果您需要持久记住文件位置,最好使用书签,这样即使用户同时重命名或移动文件,也可以找到它们。

\n
\n

免责声明:所有这些发现都是根据经验得出的,在 macOS 10.13.6 和 11.1(以及其间的系统)上进行了测试,因此您可能需要仔细检查我的发现,如果您得到不同的结果,请留下评论。

\n