请考虑以下代码段:
let url = FileManager.default.homeDirectoryForCurrentUser
let cString1 = url.absoluteString.cString(using: .utf8)
let cString2 = url.withUnsafeFileSystemRepresentation { $0 }
我们可以期望cString1
和cString2
是相等的C字符串吗?
如withUnsafeFileSystemRepresentation(_:)
的文档中所述,它将Swift字符串转换为具有UTF8编码的C字符串。这与cString(using: .utf8)
正在做的完全相同。
两者都将Swift字符串转换为UnsafePointer<Int8>?
类型。
只有Xcode会将cString(using:)
的返回类型显示为[CChar]?
,其中CChar
是Int8
的类型别名。据我所知,Swift数组也可以传递给UnsafePointer
。
大多数情况下,我只使用cString(using: .utf8)
,一切都很好但是在极少数情况下我需要因某种原因使用withUnsafeFileSystemRepresentation(_:)
,否则C函数不理解字符串。
那么我在这里失踪的区别是什么?
答案 0 :(得分:4)
来自Apple File System Guide FAQ:
为避免在文件名中使用不匹配的Unicode规范化(对于iOS 10.3.0,10.3.1和10.3.2)在代码中引入错误,请执行以下操作:
- 在与文件系统交互时,使用NSFileManager和NSURL等高级Foundation API。
- 使用POSIX open(2)等低级文件系统API创建和打开文件时,或者在文件系统外部存储文件名时,使用NSURL对象的fileSystemRepresentation属性。
如果路径需要withUnsafeFileSystemRepresentation()
传递给POSIX调用,例如open()
,stat()
,unlink()
,
getxattr()
,...并保证正确的Unicode
系统调用的规范化表单已创建。
简单示例(删除文件,如果存在,忽略错误):
url.withUnsafeFileSystemRepresentation {
_ = unlink($0)
}
请参阅Write extend file attributes swift example了解&#34;真实&#34;例。注意
let cString2 = url.withUnsafeFileSystemRepresentation { $0 }
无效,因为C字符串在块的上下文之外无效。
这是一个证明两个API可以提供的示例 不同的C字符串:
let path = "Café".precomposedStringWithCanonicalMapping
let url = URL(fileURLWithPath: path)
path.withCString { s1 in
url.withUnsafeFileSystemRepresentation { s2 in
print(strcmp(s1, s2) == 0) // false
}
}
建议使用Foundation API(FileManager
,URL
,...),
然后你不必关心文件系统表示。