34

我的应用程序在 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
4

6 回答 6

31

我从调试器中尝试了这个,发现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听起来仍然是一个很好的解决方案,适用于模拟器和设备,并且如果发生变化,将来应该可以继续工作。

于 2013-04-15T23:39:43.130 回答
7

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

在撰写文档时,该文档非常无用,但看起来它与NSURL'sstandardized属性等效。

于 2017-01-26T16:28:27.740 回答
4

要实际回答您的问题:

我相信/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. 有一次,他们开始为不同的模拟器版本使用不同的目录。

于 2013-02-21T02:12:52.697 回答
3

/var is just a symlink to /private/var. So the first path is the logical path that you tried to access. The second is that same path with symlinks expanded.

于 2013-02-21T01:02:08.497 回答
0
  1. 在我的情况下,使用 FileManager.default.fileExists 检查文件是否已经存在,但我使用的是 .absoluteString/ "()"。而不是 .path 将 URL 作为字符串传递。
  2. 当我使用打印文档目录中文件的路径时

让 fileURLs = 试试 fileManager.contentsOfDirectory(at:

它打印为/private/var

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

它打印为/var

  1. 这种路径上的差异使我感到困惑。
  2. 如上所述,它只是symlink。即两条路径是相同的。

:)

于 2018-07-18T10:04:36.733 回答
0

一个从缓存中删除文件的函数(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
}
于 2020-06-21T17:36:52.943 回答