iOS 文件路径上的 /private 前缀表示啥?

Posted

技术标签:

【中文标题】iOS 文件路径上的 /private 前缀表示啥?【英文标题】:What does the /private prefix on an iOS file path indicate?iOS 文件路径上的 /private 前缀表示什么? 【发布时间】:2013-02-06 05:17:41 【问题描述】:

我的应用在 iPhone 上运行时出现错误,但在模拟器上运行时却没有。我使用主目录路径的长度来提取 /Documents 中文件的相对路径。不幸的是,这并不总是在 iPhone 上正常工作,因为前缀“/private”被添加到主路径中。但是,无论有无前缀,都可以引用同一个文件。下面的代码演示了这种不一致。 “/private”的用途是什么,ios什么时候提供?

- (IBAction)testHomepath:(id)sender 
    NSFileManager *fmgr = [NSFileManager defaultManager];
    NSString  *homePath = [NSString stringWithFormat:@"%@/Documents",NSHomeDirectory()];
    NSString  *dirPath  = [homePath stringByAppendingPathComponent:@"TempDir"];
    NSURL     *dirURL   = [NSURL fileURLWithPath:dirPath];
    NSString  *filePath = [dirPath  stringByAppendingPathComponent:@"test.jpg"];
    [fmgr createDirectoryAtPath:dirPath withIntermediateDirectories:NO attributes:nil error:nil];
    [fmgr createFileAtPath:filePath contents:nil attributes:nil];
    NSArray *keys  = [[NSArray alloc] initWithObjects:NSURLNameKey,nil];
    NSArray *files = [fmgr contentsOfDirectoryAtURL:dirURL includingPropertiesForKeys:keys options:0 error:nil];
    NSURL *f1 = (files.count>0)? [files objectAtIndex:0] : 0;
    NSURL *f2 = (files.count>1)? [files objectAtIndex:1] : 0;
    bool   b0 = [fmgr fileExistsAtPath:filePath];
    bool   b1 = [fmgr fileExistsAtPath:f1.path];
    bool   b2 = [fmgr fileExistsAtPath:f2.path];

    NSLog(@"File exists=%d at path:%@",b0,filePath);
    NSLog(@"File exists=%d at path:%@",b1,f1.path);
    NSLog(@"File exists=%d at path:%@",b2,f2.path);

在 iPhone 上运行时将以下内容写入日志。我手动间隔输出以显示第 1 行和第 2 行之间的差异。

2013-02-20 16:31:26.615 Test1[4059:907] File exists=1 at path:        /var/mobile/Applications/558B5D82-ACEB-457D-8A70-E6E00DB3A484/Documents/TempDir/test.jpg
2013-02-20 16:31:26.622 Test1[4059:907] File exists=1 at path:/private/var/mobile/Applications/558B5D82-ACEB-457D-8A70-E6E00DB3A484/Documents/TempDir/test.jpg
2013-02-20 16:31:26.628 Test1[4059:907] File exists=0 at path:(null)

在模拟器上运行时写入日志如下(无“/private”):

2013-02-20 16:50:38.730 Test1[7224:c07] File exists=1 at path:/Users/kenm/Library/Application Support/iPhone Simulator/6.1/Applications/C6FDE177-958C-4BF5-8770-A4D3FBD281F1/Documents/TempDir/test.jpg
2013-02-20 16:50:38.732 Test1[7224:c07] File exists=1 at path:/Users/kenm/Library/Application Support/iPhone Simulator/6.1/Applications/C6FDE177-958C-4BF5-8770-A4D3FBD281F1/Documents/TempDir/.DS_Store
2013-02-20 16:50:38.733 Test1[7224:c07] File exists=1 at path:/Users/kenm/Library/Application Support/iPhone Simulator/6.1/Applications/C6FDE177-958C-4BF5-8770-A4D3FBD281F1/Documents/TempDir/test.jpg

【问题讨论】:

你能做的最糟糕的事情就是对你的应用程序的 Documents 目录的路径是什么或将会是什么做出任何假设。期望该路径的特定长度更糟。只需确定文档路径并将其从完整路径中删除即可获取您的相对路径。 @maddy,我没有假设特定的长度,只是 /Documents 的路径不会改变,这被 IOS 添加 /private 所违反,因为 Kevin Ballard 在下面指出只是一个符号链接.我来自 Windows,我从未见过这种情况发生。现在,我在 IOS 给我的任何路径中找到 /NSHomeDirectory()/Documents 的子字符串,然后在相对路径之后调用路径字符串。您对此有任何问题或知道获取相对路径的更好方法吗? 您的问题是:我使用的是主目录路径的长度。您应该始终使用相对于 Documents 目录的路径。你绝不能坚持完整的路径。如果您只有相对目录,则无需处理任何内容。 @maddy,我只保留相对路径,但 NSFileManager contentsOfDirectoryAtURL 返回完整路径。我需要删除 /Documents 之前的内容以获取我可以保留的相对路径。 请改用NSFileManager contentsOfDirectoryAtPath:error:。返回的路径列表与您获取内容的路径有关。 【参考方案1】:

从缓存中删除文件的函数 (Swift 5)。我遇到了很多问题,使用 URL 解决了 /private 问题。

class func removeFileFromCache( filePattern: String ) -> Bool 
    // find filename with pattern
     
    do 
        let cachePath = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
        let filePathUrl = URL( fileURLWithPath: filePattern )
        let originalFilename = filePathUrl.lastPathComponent
        let newFilePath = cachePath.appendingPathComponent( originalFilename ).path
       
        try FileManager.default.removeItem(atPath: newFilePath )
        print("file \( filePattern ) succesfull removed.",classname:URL(fileURLWithPath: #file).lastPathComponent )
        
     catch let error as NSError 
        print("Error \(error)",classname:URL(fileURLWithPath: #file).lastPathComponent )
        return false // all is not well
    
    
    return true

【讨论】:

【参考方案2】:
    在我使用 FileManager.default.fileExists 检查文件是否已经存在但我使用的是 .absoluteString/"()" 的情况下。而不是 .path 将 URL 作为字符串传递。 当我使用打印文档目录中的文件路径时

让 fileURLs = 试试 fileManager.contentsOfDirectory(at:

打印为/private/var

让 DocumentDirURL = 试试! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, properFor: nil, create: true)

打印为/var

    这种路径差异让我感到困惑。 如上所述,它只是符号链接。即两条路径相同。

:)

【讨论】:

【参考方案3】:

Swift 3 中,URL 具有 standardizedFileUrl 属性,它将删除任何符号链接并解析路径中的相关部分,例如 ./

在撰写本文时,documentation 相当无用,但看起来它等同于 NSURL's standardized 属性。

【讨论】:

注意:URL 有 2 个相似的属性 - standardized 不起作用,但 standardizedFileUrl 起作用!【参考方案4】:

我从调试器中尝试了这个,发现 URLByResolvingSymlinksInPath “修复”了 /private/ 添加。

(lldb) p (NSURL *)[NSURL fileURLWithPath:@"/private/var" isDirectory:YES]
(NSURL *) $1 = 0x1fd9fc20 @"file://localhost/private/var/"
(lldb) po [$1 URLByResolvingSymlinksInPath]
$2 = 0x1fda0190 file://localhost/var/

(lldb) p (NSURL *)[NSURL fileURLWithPath:@"/var" isDirectory:YES]
(NSURL *) $7 = 0x1fd9fee0 @"file://localhost/var/"
(lldb) po [$7 URLByResolvingSymlinksInPath]
$8 = 0x1fda2f50 file://localhost/var/

如您所见,file://localhost/var 是我们真正想要的。

因此,/private/var 似乎是指向/var 的符号链接。 然而,@Kevin-Ballard 指出这不是真的。我确认他是正确的,/var/private/var 的符号链接(叹气)

(lldb) p (NSDictionary *)[[NSFileManager defaultManager] attributesOfItemAtPath:@"/var" error:nil]
(NSDictionary *) $3 = 0x1fda11b0 13 key/value pairs
(lldb) po $3
$3 = 0x1fda11b0 
    ...
    NSFileType = NSFileTypeSymbolicLink;


(lldb) p (NSDictionary *)[[NSFileManager defaultManager]   attributesOfItemAtPath:@"/private/var" error:nil]
(NSDictionary *) $5 = 0x1fda4820 14 key/value pairs
(lldb) po $5
$5 = 0x1fda4820 
    ...
    NSFileType = NSFileTypeDirectory;

所以URLByResolvingSymlinksInPath 在这里做了一些有趣的事情,但现在我们知道了。对于这个特殊的问题,URLByResolvingSymlinksInPath 听起来仍然是一个很好的解决方案,适用于模拟器和设备,并且如果将来发生变化,应该会继续工作。

【讨论】:

/var 实际上也是 iOS 上/private/var 的符号链接。 -URLByResolvingSymlinksInPath 可能会以某种方式对其进行特殊处理以提供更规范的路径。 热烈讨论;我在 PDF 查看器中加载文件时遇到了问题,这一切都围绕着 simlink。一旦我遇到这个解释,解决方案就会跳出来,问题就解决了。 Apple 文档表明 URLByResolvingSymlinksInPath 删除了前导 /private。 developer.apple.com/library/ios/documentation/Cocoa/Reference/… 为我解决了所有路径问题【参考方案5】:

真正回答你的问题:

我相信/private 是他们发布 OS X 时添加的前缀(我认为 NeXTStep 中没有,但它已经 几十年了)。似乎存在 etcvartmp(奇怪的是,tftpboot;我不知道我的 PBG4 可以做到这一点),也许用户不会想知道这个愚蠢的文件夹是什么被称为etc 并尝试将其删除。

在设备上,Apple 决定将用户数据存储在 /private/var/mobile(用户名是“mobile”)中。我不确定他们为什么不选择 /Users/mobile 或只选择 /mobile,但它并不比 /var/mobile 在“普通”Unix 上更重要。

在模拟器上,您的用户帐户不能写信给/var(有充分的理由)。用户数据存储在~/Library/Application Support/iPhone Simulator 的某个位置。有一次,他们开始为不同的模拟器版本使用不同的目录。

【讨论】:

【参考方案6】:

/var 只是/private/var 的符号链接。因此,第一个路径是您尝试访问的逻辑路径。第二个是扩展符号链接的同一路径。

【讨论】:

感谢您的提示,但似乎恰恰相反。看我的回答。 @Skotch:实际上不是。请参阅我对您的回答的评论。 /var 在 Mac OS X 上长期以来一直是 /private/var 的符号链接。在 iOS 出现之前就是这样。

以上是关于iOS 文件路径上的 /private 前缀表示啥?的主要内容,如果未能解决你的问题,请参考以下文章

Java IO详解(一)------File 类

pro 前缀 啥 意思,与pre的区别

IO----File类

Java IO详解

字典树(前缀树)-Java实现

P4551 最长异或路径 (01字典树,异或前缀和)