在我自己的测试中(在 10.13.6、10.14.6 和 10.15b7 上),@vadian 的解决方案不适用于文件夹名称组件包含“/”(在 Finder 中查看时)的路径,然后出现在 POSIX 路径中作为“:”,在 HFS 路径中作为“/”。
错误演示
这是一个快速测试程序,您可以通过在 Xcode 中创建一个新的“命令行”项目来构建它:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSString *posixPath = @"/EndsInSlash:";
NSURL *url = [NSURL fileURLWithPath:posixPath];
if (url == nil) {
NSLog(@"Oops, this went wrong");
} else {
CFStringRef hfsPath = CFURLCopyFileSystemPath((CFURLRef)url, 1);
NSString *res = (NSString *)CFBridgingRelease (hfsPath);
NSLog(@"HFS path: <%@>", res);
}
}
return 0;
}
当您运行它时,您可能会看到打印的正确结果,即以“/”结尾的路径。但是,只有当文件夹不存在时才有效。因此,在您的根文件夹中创建一个名为“EndsInSlash/”的文件夹(不是文件!)并再次运行该应用程序 - 现在生成的路径不再以“/”结尾。
解决方法
下面是一个“智能”函数,它尽可能使用更快的CFURLCopyFileSystemPath() 函数,即除非“:”出现在 POSIX 路径中 - 在这种情况下,它通过拆分 POSIX 路径自行执行转换到其组件中,将它们单独转换(将“:”替换为“/”),添加卷名,然后再次合并组件。尽管有弃用警告,但这似乎在 macOS 10.15 (Catalina) 上也能正常工作。
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
static NSString* stringWithHFSUniStr255(const HFSUniStr255* hfsString)
{
CFStringRef stringRef = FSCreateStringFromHFSUniStr(nil, hfsString);
NSString* result = CFBridgingRelease(stringRef);
return result;
}
NSString* hfsPathFromPOSIXPath (NSString *posixPath)
{
if (posixPath == nil) return @"";
if ([posixPath containsString:@":"]) {
// slow version, but can handle ":" appearing in path components
NSString *result = nil;
FSRef ref;
Boolean isDir;
if (FSPathMakeRef ((const UInt8*)posixPath.UTF8String, &ref, &isDir) == noErr) {
HFSUniStr255 elemName;
FSCatalogInfo catInfo;
NSMutableArray<NSString*> *elems = [NSMutableArray arrayWithCapacity:16];
while (FSGetCatalogInfo (&ref, kFSCatInfoNodeID, &catInfo, &elemName, nil, &ref) == noErr) {
[elems insertObject: stringWithHFSUniStr255(&elemName) atIndex:0];
if (catInfo.nodeID == 2) break;
}
result = [elems componentsJoinedByString:@":"];
}
return result;
} else {
// see https://stackoverflow.com/a/45085776/43615
NSURL *url = [NSURL fileURLWithPath:posixPath];
if (url == nil) {
// could not convert because the path doesn't exist
return nil;
}
CFStringRef hfsPath = CFURLCopyFileSystemPath((CFURLRef)url, kCFURLHFSPathStyle);
return (NSString *)CFBridgingRelease (hfsPath);
}
}
#pragma clang diagnostic pop
另见
讨论 AppleScript 的相关错误,并提供解决方法:https://forum.latenightsw.com/t/xxx/2097
向 Apple 提交的错误报告:http://www.openradar.me/radar?id=4994410022436864