我应该何时使用NSURLCanonicalPathKey?

时间:2019-05-19 09:10:36

标签: macos cocoa url appkit core-foundation

在macOS 10.12中,NSURLCanonicalPathKey已添加到NSURL中。该文档指出:

  

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

除此之外,我看到的唯一其他文档/信息来自a Swift Forum post,其中指出:

  

您可能想看看.canonicalPathKey(NSURLCanonicalPathKey)。在Apple平台上,/ private /中存在许多标准UNIXy路径,并且根目录具有相应的符号链接。因此,/ etc /实际上是/ private / etc /。如果您无法规范化路径,则可能会被绊倒。

对我来说这似乎很重要,但是我很惊讶它仅在10.12中引入。我只依靠NSURLPathKey.path或书签数据来解析URL,而从来没有问题

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

  • 如果我将路径信息以字符串形式存储在数据库中,应该 是否存储.pathNSURLCanonicalPathKey的值?

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

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

  • NSURLCanonicalPathKeyURLByStandardizingPathURLByResolvingSymlinksInPath的比较如何? function factorial(num, result) { console.log('num', num) if (num === 0) { console.log('res ', result); return result; } else { result = result * num; console.log(result) factorial(--num, result); } } let res = factorial(3, 1) console.log(res) model = Resnet3DBuilder.build_resnet_18((128, 96, 96, 3), nClass[0]) model.load_weights('drive/app/models/3d_resnet_modelq.hdf5') 似乎在做相同的事情或相反的事情...(?)

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

1 个答案:

答案 0 :(得分:3)

这取决于您打算如何使用路径:

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

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

示例

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

<头>
输入 URLByStandardizingPath NSURLCanonicalPathKey
/private/var /var /private/var
/var /var /private/var

Unicode 规范化

以下示例使用准备好的 APFS 卷,其中包含具有字母“ü”的预组合和分解表示以及符号链接的文件名。你可以download the disk image file here

目录布局如下:

$ cd /Volumes/Canonical_Normalize_Test/
$ ls -lR
total 24
-rw-r--r--  1 user  staff   19 Dec 29 19:27 decomposed_ü
-rw-r--r--  1 user  staff   19 Dec 29 19:27 precomposed_ü
drwxr-xr-x  4 user  staff  128 Dec 29 19:36 symlink_target_dir
lrwxr-xr-x  1 user  staff   18 Dec 29 19:36 symlink_to_dir -> symlink_target_dir
-rwxr-xr-x@ 1 user  staff  763 Dec 15 16:28 unicode_composition_check.sh

./symlink_target_dir:
total 0
lrwxr-xr-x  1 user  staff  17 Dec 29 19:36 decomposed_ü -> ../decomposed_ü
lrwxr-xr-x  1 user  staff  17 Dec 29 19:36 precomposed_ü -> ../precomposed_ü

文件“unicode_composition_check.sh”是一个创建两个“...ü”文件的脚本,一个使用NFD命名,另一个使用NFC(不幸的是,脚本命名不当)。

输入是:

/Volumes/Canonical_Normalize_Test/symlink_to_dir/precomposed_\U00fc

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

<头>
方法 结果
文件系统表示 /Volumes/Canonical_Normalize_Test/symlink_to_dir/precomposed_u\U0308
URLByStandardizingPath /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

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

  1. 它们似乎都将路径规范化为 NFD,即“ü”在所有情况下都被分解。这对于常规不区分大小写的卷来说是必要和正常的,因为文件名的查找 是规范化不敏感的。但是:对于区分大小写的卷,不得更改组成,虽然我没有测试过这一点,但我假设上述所有功能都会检测卷的区分大小写模式并做出相应的行为。

  2. 如果我们以后想通过路径重新识别目标项,只有 NSURLCanonicalPathKey 给出了所需的正确结果(不管使用哪种 Unicode 组合以及路径是否包含指向目录的符号链接) :它解析目录符号链接,但不是 symlink_target_dir 内的最终符号链接。如果它确实解析了最终路径元素(如 URLByResolvingSymlinksInPath 所做的那样),您将无法定位符号链接文件。

  3. NSString 的 fileSystemRepresentation 不会改变路径(但会对其进行标准化),而 NSURL 的 URLByStandardizingPath 在某些情况下会改变路径(例如,通过从某些根文件夹中删除“/private”)。< /p>

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

结论

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

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

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

最后,如果你只是想看看两个路径是否指向同一个文件,使用其他不依赖路径的方式更安全。见this answer。如果您需要永久记住文件位置,最好使用 bookmarks,这样即使用户在此期间重命名或移动了文件,也能找到它们。


免责声明:所有这些发现都是凭经验发现的,在 macOS 10.13.6 和 11.1(以及介于两者之间的系统)上进行了测试,因此您可能需要仔细检查我的发现,如果您有不同意见,请发表评论结果。