文件从NSLibraryDirectory中消失 [英] Files disappearing from NSLibraryDirectory

查看:118
本文介绍了文件从NSLibraryDirectory中消失的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将一些文件存储在iOS应用程序的Library目录中,使用以下方法构建它。最后,我可以调用 [MyClass dataDirectory] ​​进行文件处理,一切顺利。但是,我最近发现,有些文件似乎神秘地从这个目录中消失了。根据文档,这应该是不是这样的。这是存储持久文件的安全位置吗?

I'm storing some files in the Library directory in an iOS app, using the following methods to construct it. In the end, I can call [MyClass dataDirectory] to do my file handling and all is well. I've recently discovered, however, that some files seem to be mysteriously disappearing out of this directory. According to the documentation, this should not be the case. Is this a safe place to store persistent files?

此目录的控制台输出为:〜/ var / mobile / Containers / Data / Application / {id} / Library / Data

The console output of this directory is: ~/var/mobile/Containers/Data/Application/{id}/Library/Data

+ (NSString*)libraryDirectory
{
    return [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
}

+ (NSString*)dataDirectory
{
    NSString* dir = [[self libraryDirectory] stringByAppendingPathComponent:@"Data"];
    BOOL isDir=NO;
    NSError * error = nil;
    NSFileManager *fileManager = [NSFileManager new];

    if (![fileManager fileExistsAtPath:dir isDirectory:&isDir] && isDir)
    {

        [[NSFileManager defaultManager] createDirectoryAtPath:dir
                                  withIntermediateDirectories:YES
                                                   attributes:nil
                                                        error:&error];
    }

    [self addSkipBackupAttributeToItemAtURL:[NSURL fileURLWithPath:dir isDirectory:YES]];

    if (error != nil) {
        DDLogError(@"Fatal error creating ~/Library/Data directory: %@", error);
    }
    return dir;
}

跳过方法:

+ (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL
{
    if ([[NSFileManager defaultManager] fileExistsAtPath:[URL path]])
    {
        assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]);

        NSError *error = nil;
        BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES]
                                      forKey: NSURLIsExcludedFromBackupKey error: &error];
        if(!success){
            DDLogError(@"Error excluding %@ from backup %@", [URL lastPathComponent], error);
        }
        return success;
    }
    return YES;
}


推荐答案

在您发布的代码中,第一个问题在这里:

In the code you posted, the first problem is here:

if(![fileManager fileExistsAtPath:dir isDirectory:& isDir]&& isDir)

在评估此点时, isDir 将默认为NO,并将设置如果文件不存在或不是目录,则返回NO。这将阻止创建目录。删除&& isDir 或更改为 || !isDir 获得你想要的逻辑。

At the point where this is evaluated, isDir will default to NO, and will be set to NO if the file does not exist or is not a directory. This will prevent the directory from being created. Remove && isDir or change to || !isDir to get the logic you want.

现在问你原来的问题:

是。默认情况下备份 NSLibraryDirectory 。要遵守 iOS数据存储指南,应用程序不应存储用户在该位置创建的数据,但它是存储应用程序数据的安全位置。 NSApplicationSupportDirectory 是一个通常位于 NSLibraryDirectory 内的目录,是存储此类数据的首选位置。该位置中的数据将被备份,并将在应用程序和操作系统更新期间迁移。

Yes. NSLibraryDirectory is backed up by default. To comply with the iOS Data Storage Guidelines an application should not store user-created data in that location, but it is a safe place to store application data. NSApplicationSupportDirectory is a directory that is generally within the NSLibraryDirectory, and is the preferred place to store this kind of data. Data within that location will be backed up, and will be migrated during application and OS updates.

iOS数据存储指南文件系统编程指南,以及 iOS应用编程指南 all提供有关放置文件的位置的指导,以及如何从标准文件系统位置备份文件。

The iOS Data Storage Guidelines, File System Programming Guide, and App Programming Guide for iOS all provide guidance on where to put files, and how they will be backed up from standard file system locations.

除非这些文件的文件已经 NSURLIsExcludedFromBackupKey / kCFURLIsExcludedFromBackupKey reso urce元数据值已更改。然后它变得复杂得多。

Unless those files have had their NSURLIsExcludedFromBackupKey/kCFURLIsExcludedFromBackupKey resource metadata value altered. Then it gets much more complicated.

通常,如果文件在...之外可以备份文档目录,系统假定它也可以在低空间或其他条件下清除它。这就是为什么在文件上将 NSURLIsExcludedFromBackupKey 设置为YES允许文件即使在低存储条件下也能保留的原因。如果您的应用程序将 NSURLIsExcludedFromBackupKey 设置为YES,那么您的应用程序将承担该文件生命周期的责任。

Generally, if a file outside of a Documents directory can be backed up, the system assumes it can also purge it under low space or other conditions. This is why setting NSURLIsExcludedFromBackupKey to YES on a file allows the file to persist even in low storage conditions. If your application sets NSURLIsExcludedFromBackupKey to YES for a file, your application assumes responsibility for the life of that file.

这里的问题是备份过程和清除过程不遵循相同的逻辑。 Apple的文档表明,为了控制备份行为,可以在目录上设置 NSURLIsExcludedFromBackupKey 。该目录的子级将有效地继承该资源值(实际上,这可能不准确)。但是,清除过程似乎没有相同的行为。它可能无法检查父目录的备份排除并将其应用于子目录,因此如果文件没有 NSURLIsExcludedFromBackupKey 明确设置,则可能会清除它。

The catch here is that the backup process and the purge process do not follow the same logic. Apple's documentation indicates that for the purposes of controlling the backup behavior, it is possible to set NSURLIsExcludedFromBackupKey on a directory. The children of that directory will effectively inherit that resource value (in practice, this may not be accurate). The purge process, however, does not seem to have the same behavior. It may not check the backup exclusions of the parent directories and apply it to children, and as a result if a file does not have NSURLIsExcludedFromBackupKey explictly set it may be purged.

这变得更加复杂。如果您要阅读常量文档 NSURLIsExcludedFromBackupKey 您会看到:

This gets even more complicated. If you were to read the documentation for the constant NSURLIsExcludedFromBackupKey you would see:


通常对用户文档进行的一些操作会导致此属性重置为false;因此,不要在用户文档上使用此属性。

Some operations commonly made to user documents cause this property to be reset to false; consequently, do not use this property on user documents.

这实际上不仅适用于用户文档。例如,如果您要对文件执行原子写操作,例如:

This actually applies to much more than user documents. For example, if you were to perform an atomic write on a file such as:

[thing writeToURL:URL atomically:YES encoding:NSUTF8StringEncoding error :& error]

如果 URL 的文件 NSURLIsExcludedFromBackupKey 在写入之前设置为YES,现在看起来设置为NO。像这样的原子写入将首先创建一个临时文件,写入该文件,并用新文件替换原始文件。这样做不会保留文件和URL资源标志。原始文件设置了 NSURLIsExcludedFromBackupKey 资源值,现在在同一位置新创建的文件不会。这只是一个例子;许多基金会API都会执行这样的原子写入。

If the file at URL had NSURLIsExcludedFromBackupKey set to YES before the write, it would now appear to be set to NO. An atomic write like this will first create a temporary file, write to that, and replace the original with the new file. In doing so, file and URL resource flags are not preserved. The original file had the NSURLIsExcludedFromBackupKey resource value set, the newly created file at the same location now does not. This is just one example; many Foundation APIs perform atomic writes like this implictly.

有些情况会变得更加复杂。更新应用程序时,会将其安装到具有新应用程序容器路径的新位置。迁移旧应用程序容器内的数据。关于在更新过程中可能迁移或不迁移的内容的保证很少。它可能是一切,它可能只是一些东西。特别是没有关于如何处理标有 NSURLIsExcludedFromBackupKey 资源属性的文件或目录的指导。在实践中,似乎这些文件通常是最不可能迁移的文件,并且当它们被迁移时,很少保留 NSURLIsExcludedFromBackupKey 属性。

There are scenarios where this gets even more complex. When an application is updated it is installed into a new location with a new application container path. Data inside the old application container is migrated. There are few guarantees regarding what may or may not be migrated as part of the update process. It may be everything, it may be only some things. In particular there are is no guidance concerning how files or directories marked with the NSURLIsExcludedFromBackupKey resource attribute will be treated. In practice it seems that these are often the least likely files to be migrated, and when they are migrated the NSURLIsExcludedFromBackupKey attribute is rarely preserved.

操作系统更新也是一个问题。历史上,Over-the-Air更新存在问题,导致 NSURLIsExcludedFromBackupKey 资源属性被有效清除或忽略。 主要操作系统更新将清除设备并从备份恢复 - 这相当于迁移到新硬件。标有 NSURLIsExcludedFromBackupKey 资源属性的文件将不会被迁移,应用程序将不得不重新创建它们。

OS updates are also an issue. Historically Over-The-Air updates have been problematic and have caused the NSURLIsExcludedFromBackupKey resource attribute to be effectively cleared or ignored. A "major" OS update will clear the device and restore from a backup - which is equivalent to migrating to new hardware. Files marked with the NSURLIsExcludedFromBackupKey resource attribute will not be migrated, and the application will have to re-create them.

TechNote中介绍了更新方案2285:测试iOS应用更新

因此,当使用 NSURLIsExcludedFromBackupKey 时,通常最好设置每次访问的值,并始终通过文件协调API (除非您要写入共享组容器,这是一组完全不同的问题)。如果 NSURLIsExcludedFromBackupKey 资源属性值丢失,则可以随时清除文件。理想情况下,应用程序不应该依赖于 NSURLIsExcludedFromBackupKey 或操作系统如何(或可能不)处理它,而是设计为可以根据需要重新创建数据。这可能并不总是可能的。

Because of this, when using NSURLIsExcludedFromBackupKey it is generally best to set the value on every access, and as always should be done through the File Coordination APIs (unless you are writing to a shared group container, which is an entirely different set of issues). If the NSURLIsExcludedFromBackupKey resource attribute value is lost files can be purged at any time. Ideally an application should not depend on the NSURLIsExcludedFromBackupKey or how the OS may (or may not!) handle it, but instead be designed such that the data could be recreated on demand. That may not always be possible.

从您的问题和您发布的代码中可以清楚地看出,您在某种程度上依赖于 NSURLIsExcludedFromBackupKey 确保您的文件具有应用程序控制的生命周期。正如您从上面所看到的,情况可能并非总是如此:有许多常见的情况,资源属性值可以消失,并且随之而来的是您的文件。

It's clear from your question and the code that you posted that you are somewhat dependant on NSURLIsExcludedFromBackupKey ensuring that your file(s) have an application-controlled lifetime. As you can see from the above, that may not always be the case: there are many, many common scenarios where that resource attribute value can disappear, and with it your files.

值得注意的是,NSFileProtection属性的工作方式相同,并且可以在相同的场景中消失(还有一些)。

It is also worth noting that NSFileProtection attributes work the same way, and can disappear in the same scenarios (and a few more).

根据您的问题,代码以及您所看到的行为描述:

Based on your question, code, and the description of the behavior you are seeing:


  • 在包含您要保留的文件的目录上设置 NSURLIsExcludedFromBackupKey 值可能不足以阻止它们被清除。在每次访问实际文件时设置 NSURLIsExcludedFromBackupKey 是明智的,而不仅仅是父目录。还要尝试确保在对文件进行任何写入之后设置此资源值,尤其是通过可能正在执行原子写入的高级API等。

  • Setting the NSURLIsExcludedFromBackupKey value on the directory containing the file(s) you are interested in preserving may not be enough to prevent them from being purged. It would be wise to set NSURLIsExcludedFromBackupKey on every access to the actual files, rather than just a parent directory. Also attempt to ensure this resource value is set after any write to the file, especially through a high level API that may be doing atomic writes, etc.

全部NSFileManager和文件读/写操作应该使用文件协调。即使在单线程的应用程序中,也会有其他进程与您的文件交互。进程类似于在低空间条件下运行备份或清除文件的守护程序。在 -fileExistsAtPath: -setResourceValue:forKey之间:错误:另一个进程可能会改变,删除或移动你的文件及其属性。 -setResourceValue:forKey:error:实际上会返回YES并且在没有做任何事情的情况下没有错误,例如文件不存在。

All NSFileManager and file reading/writing operations should use file coordination. Even in an application that is single threaded there will be other processes interacting with "your" files. Processes like the daemons that run backups or purge files during low space conditions. Between your -fileExistsAtPath: and the -setResourceValue:forKey:error: another process could alter, delete, or move your file and its attributes. -setResourceValue:forKey:error: will actually return YES and no error in many cases where it did nothing, like the file not existing.

标有 NSURLIsExcludedFromBackupKey 的文件和目录是管理应用程序的责任。应用程序仍应在适当的时间清除这些文件或其内容,或对其增长设置限制。如果查看设备上的每个应用程序磁盘使用情况信息,您可能会猜到某些应用程序的名称无法正确执行此操作。

Files and directories marked with NSURLIsExcludedFromBackupKey are the responsibility of the application to manage. The application should still purge those files or their contents at some appropriate time, or set limits on their growth. If you look at the per-application disk usage information on a device, you can probably guess the names of some applications that do not do this correctly.

测试更新方案,如 TechNote 2285中所述:测试iOS应用更新。经常。理想情况下,iOS模拟器将具有类似于模拟内存警告的模拟低磁盘空间功能,但目前它没有。

Test update scenarios as described in TechNote 2285: Testing iOS App Updates. often. Ideally the iOS Simulator would have a "Simulate Low Disk Space" capability similar to simulating memory warnings, but at this time it does not.

如果可能,请更改应用程序逻辑,以便在丢失时重新创建这些文件。

If at all possible, alter application logic to recreate these files if they go missing.

这篇关于文件从NSLibraryDirectory中消失的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆