【问题标题】:NSFileManager removeItemAtPath: error: did not actually free disk spaceNSFileManager removeItemAtPath:错误:实际上并没有释放磁盘空间
【发布时间】:2012-07-27 08:42:48
【问题描述】:
NSFileManager* fileManager = [NSFileManager defaultManager];
NSURL* url = [[fileManager URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask] lastObject];
NSString* directory = [url path];
NSString* filePath = [directory stringByAppendingPathComponent:FILE_NAME];
if ([fileManager fileExistsAtPath:filePath])
{
    [fileManager removeItemAtPath:filePath error:nil];
}   

这是我的代码。执行时,文件被删除,但空间仍然被占用。这是将内容存储到文件中的代码。

NSFileManager* fileManager = [NSFileManager defaultManager];
NSURL* url = [[fileManager URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask] lastObject];
NSString* directory = [url path];
NSString* filePath = [directory stringByAppendingPathComponent:FILE_NAME];
NSArray* oldArray = nil;
if ([fileManager fileExistsAtPath:filePath])
{
    oldArray = [[NSArray alloc] initWithContentsOfFile:filePath];
    [fileManager removeItemAtPath:filePath error:nil];
}
NSMutableArray* mergeArray = [[NSMutableArray alloc] initWithArray:arrayOfPersons];
[mergeArray addObjectsFromArray:oldArray];
if ( [mergeArray writeToFile:filePath atomically:YES]) NSLog(@"Written");

顺便说一句,存储一个只有 1 个对象的数组需要 1 MB(一个 NSDictionary 有 2 个键)。有没有更便宜的存储方式?

【问题讨论】:

  • 我使用了这个确切的代码,它工作得很好。具有两个键和两个对象的字典也是 264 字节。
  • 而不是 nil 将 NSError 对象传递给 [fileManager removeItemAtPath:filePath error:nil]; 以获取错误参数并检查它所说的内容。
  • 你的意思是你执行了代码,文件存在吗?还是文件被删除但空间仍然被占用?
  • @cloosen,文件不存在,但空间仍然被占用
  • @borrrden,在我的例子中是 1MB,两个对象是一个 NSString 和一个 NSNumber。代码工作正常,但空间仍然被占用。

标签: ios nsfilemanager


【解决方案1】:

您需要更加小心地进行实验。 unix 文件系统对文件做了很多事情。事实上,当你“删除”一个文件时,你所做的只是将它从文件系统中取消链接。如果该文件使用另一个文件描述符打开,则在操作系统的任何位置,它将保持打开状态。

此外,还有很多优化可以重用文件节点。仅仅因为您删除了一个文件,并不意味着空间会自动返回。它可能出于多种原因在您的应用程序中“保留”,以供其他文件使用。在文件系统需要它之前将其返回给文件系统是没有意义的。

settings->general->usage 是对文件系统利用率的粗略测量。更好的测量方法是直接访问文件和文件系统的属性。

以您的代码为基础,考虑以下几点:

- (NSString*)workingDirectory {
    NSFileManager* fileManager = [NSFileManager defaultManager];
    NSURL* url = [[fileManager URLsForDirectory:NSCachesDirectory
                                      inDomains:NSUserDomainMask] lastObject];
    return [url path];
}

- (NSString*)filePath {
    return [[self workingDirectory] stringByAppendingPathComponent:FILE_NAME];
}

现在,你可以看到整个文件系统的所有属性:

NSDictionary *attributes = [[NSFileManager defaultManager]
    attributesOfFileSystemForPath:[self workingDirectory] error:0];
NSLog(@"file system attributes: %@", attributes);

以及带有以下内容的特定文件:

NSDictionary *attributes = [[NSFileManager defaultManager]
    attributesOfItemAtPath:[self filePath] error:0];
NSLog(@"file attributes: %@", attributes);

注意NSFileSystemFreeSizeNSFileSize

运行您的应用,并转储这两个值。创建您的文件,然后再次转储它们。删除文件,然后再次转储。

毕竟,您实际上可能会看到NSFileSystemFreeSize 上升,即使在删除之后也是如此。请记住,系统本身正在创建临时文件,并且可能正在缓存这些文件系统节点以供将来使用。

如果您退出所有其他应用,您可以获得更一致的结果。然后,退出你的(双击电源按钮,X 所有正在运行的应用程序)。在执行此操作之前删除文件。

  1. 现在,在文件不存在的情况下启动您的应用程序。

  2. 转储文件系统数据。

  3. 创建文件。

  4. 转储文件系统数据。

  5. 转储文件数据。

您应该看到文件占用大约 200-250 字节,文件系统可用大小应该下降 8192。

  1. 删除文件。

  2. 转储文件系统数据。可能至少与删除文件之前一样大。

  3. 退出应用程序(不在 XCode 中 -- 双击电源,X 应用程序)。

  4. 运行应用程序。

  5. 转储文件系统数据。您应该会看到数据回到您之前开始时的状态。


总之,虽然看起来文件系统没有发布数据,但实际上已经发布了,但可能您用来查询的工具只是不知道文件系统的详细信息。

另外请注意,当应用程序运行时,它会使用大量文件系统资源来处理您未明确执行的操作。

我希望这是有道理的......

【讨论】:

  • 感谢您的回答。实际上,我无法看到我之前开始时的数据,因为这些数据似乎一直在变化。但我确实得到了一些与你说的相似的结果。您能否向我进一步解释为什么“您应该看到文件占用大约 200-250 字节,并且文件系统可用大小应该下降 8192。”。 (在我的情况下,文件 410 字节和可用大小下降了 16384。)为什么我的文件实际上很小却丢失了这么多空间?如何节省磁盘空间?目前,包含 100 个对象的数组花费了我数百 MB。
  • 您担心自己无法控制的事情。为了提高效率,文件系统以字节块的形式工作。文件系统管理所有应用程序的空间,并尝试将文件的潜在数据保持在一起。确保编写好的、高效的代码,不要担心文件系统本身的实现。即使它很糟糕(事实并非如此),你也无能为力。至于你的 100 个对象,请确保它们是有效的。您可以控制特定的文件大小,而不必完全控制文件系统分配的大小。
【解决方案2】:

您删除文件的代码看起来正确,但您在不需要时在 URL 和路径之间切换。当您尝试删除文件时,您还应该检查错误,以便了解它为什么不起作用。试试这个:

    NSFileManager   *fileManager    = [NSFileManager defaultManager];
    NSArray         *directoryURLs  = [fileManager URLsForDirectory:NSCachesDirectory 
                                                          inDomains:NSUserDomainMask];
    NSURL           *directoryURL   = [directoryURLs objectAtIndex:0];
    NSURL           *fileURL        = [directoryURL URLByAppendingPathComponent:FILE_NAME];
    if (!fileURL)
    {
        NSLog(@"Could not create URL for file.");
        return;
    }

    NSError *err = nil;
    if (![fileURL checkResourceIsReachableAndReturnError:&err])
    {
        NSLog(@"File is not reachable.\n"
               "Error: %@ %d %@", [err domain], [err code], [[err userInfo] description]);
        return;
    }

    err = nil;
    [fileManager removeItemAtURL:fileURL error:&err];
    if (err)
    {
        NSLog(@"Unable to delete existing file.\n"
              "Error: %@ %d %@", [err domain], [err code], [[err userInfo] description]);
        return;
    }

【讨论】:

  • 感谢您的建议。不幸的是,[fileManager removeItemAtURL:fileURL error:&err] 之后的错误为零。文件被删除。但空间仍然被占用。
  • 啊,那将是一个不同的问题!
【解决方案3】:

可能是 ˚FILE_NAME` 的长度大于或等于 300 个字符?前段时间这让我遇到了与 NSFileManager 类似的问题......

【讨论】:

  • 我认为在 300 以内,"file://localhost/var/mobile/Applications/4E0DED61-2FE1-4337-8F0B-461E35B1E610/Library/Caches/receiversSent"
猜你喜欢
  • 2017-08-07
  • 2010-09-24
  • 1970-01-01
  • 1970-01-01
  • 2020-03-23
  • 2023-04-10
  • 1970-01-01
  • 1970-01-01
  • 2011-05-15
相关资源
最近更新 更多