【问题标题】:Empty files in app documents directory应用文档目录中的空文件
【发布时间】:2014-10-10 19:31:21
【问题描述】:

我的应用有一个草稿表视图,显示用户保存的音频文件。对于数据源数组,我遍历草稿目录(在NSDocumentDirectory 内)。该代码工作正常,它显示了我迄今为止保存的所有文件。

问题是,就在最近,除了前两个文件之外的所有文件都是空的。空,我的意思是:当我使用 NSData 的 datatWithContentsOfFile 方法时,数据长度为 0,即 0 字节。前两个文件仍然有数据,每个文件大约 267639 b。

但是如果文件中没有数据,为什么在我遍历草稿目录时会出现?这些空文件直到最近才完好无损。什么可能导致它们变空?

以下是用于循环草稿目录的代码。

// check if drafts folders exist
BOOL draftsFoldersExist = NO;
NSError *error = nil;
NSArray *folders = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSArray *appFolderContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[folders objectAtIndex:0] error:&error];
if ([appFolderContents count] > 0 && error == nil) {
    for (NSString *item in appFolderContents) {
        if ([item isEqualToString:@"drafts"])
            draftsFoldersExist = YES;
    }
}
_draftsArray = [[NSMutableArray alloc] init];

if (draftsFoldersExist) {
    // drafts data source
    NSString *draftsPath = [NSString stringWithFormat:@"%@/drafts", [folders objectAtIndex:0]];
    NSString *draftsPathEncoded = [draftsPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *draftsPathURL = [NSURL URLWithString:draftsPathEncoded];
    // enumerate files in drafts folders
    NSArray *desiredProperties = @[NSURLIsReadableKey, NSURLCreationDateKey];
    NSArray *drafts = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:draftsPathURL includingPropertiesForKeys:desiredProperties options:0 error:&error];

    for (NSURL *item in drafts) {
        NSMutableDictionary *draftDict = [[NSMutableDictionary alloc] init];
        // name
        NSString *name = [item lastPathComponent];
        // is readable
        NSNumber *isReadableBoolValue = nil;
        [item getResourceValue:&isReadableBoolValue forKey:NSURLIsReadableKey error:&error];
        if ([isReadableBoolValue isEqualToNumber:@YES]) {
            // filename
            [draftDict setValue:[name stringByDeletingPathExtension] forKey:@"draftFilename"];
            // creation date
            NSDate *creationDate = nil;
            [item getResourceValue:&creationDate forKey:NSURLCreationDateKey error:&error];
            [draftDict setValue:creationDate forKey:@"creationDate"];
            // insert into first position of data source array
            _draftsArray = [[@[draftDict] arrayByAddingObjectsFromArray:_draftsArray] mutableCopy];
            // meta
        } else {
            NSLog(@"unreadable item: %@", name);
        }
    }
}

更新:

我根据@Joride 的建议通过管理器下载了应用程序目录的文件,发现所有文件都完好无损并带有数据。他们在这里:

2014-08-08_20-53-30.m4a
2014-08-09_19-11-08.m4a
2014-08-10_17-36-28.m4a
2014-08-11_18-53-46.m4a
2014-08-13_12-57-57.m4a
2014-08-16_20-44-33.m4a
2014-08-16_20-45-06.m4a

我想现在的问题是为什么其中一些没有使用dataWithContentsOfFile 方法显示任何数据。

我使用下面的代码来初始化 NSData 对象:

NSData *fileData = [NSData dataWithContentsOfFile:filepath options:NSDataReadingMapped error:&readingError];

对于数据为零的文件,读取错误为“无法完成操作。没有这样的文件或目录”。

【问题讨论】:

  • 您可能需要显示用于存储和检索文件的代码。
  • @Joride 你去吧
  • 太棒了。现在要去读了。在我做之前:您可以从 xcode organozer(在设备下)下载整个 app-dir。选择“检查包”以查看内容。你的文件在吗?这些文件有多大?
  • 我感觉您手动构建路径/URLS 的方式有些不对劲。我现在在 iPhone 上,所以很难阅读代码。我会在我使用 Mac 时回帖。
  • 这是一个从管理器下载文件的巧妙技巧——不知道你能做到这一点!文件确实完好无损 - 我编辑了我的答案。

标签: ios objective-c


【解决方案1】:

好的,我已经写了我认为你想要实现的目标。请注意,在此示例中,加载文件的代码在主队列上同步完成(在某些 viewDidAppear: 方法中)。这对于实际代码来说当然是一个非常糟糕的设计,因为它可能会阻塞 UI 和主队列。但这应该有效。如果是这样,那么我认为您的代码与 URLS 或加载文件时使用的选项有一些问题。如果此代码也不起作用,则有其他问题导致了问题。

给你:

#import "ViewController.h"

NSString * const kDraftsDir = @"drafts";

@interface ViewController ()
@property (nonatomic, readonly) NSMutableArray * drafts;
@end

@implementation ViewController
@synthesize drafts = _drafts;

- (NSMutableArray *) drafts
{
    if (nil == _drafts)
    {
        _drafts = [[NSMutableArray alloc] init];
    }
    return _drafts;
}
- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear: animated];
    [self readDrafts];
}
- (void) readDrafts
{
    NSFileManager * fileManager = [[NSFileManager alloc] init];
    NSError * error;
    NSURL * appDocumentDirectoryURL = [fileManager URLForDirectory: NSDocumentDirectory
                                                         inDomain: NSUserDomainMask
                                                appropriateForURL: nil
                                                           create: YES
                                                            error: &error];
    if (nil == appDocumentDirectoryURL)
    {
        NSLog(@"Error getting appDocumentDirectoryURL: %@, %@", error, [error localizedDescription]);
    }

    NSURL * draftsDirectoryURL = [appDocumentDirectoryURL URLByAppendingPathComponent:  kDraftsDir];
    if ([fileManager fileExistsAtPath: draftsDirectoryURL.path isDirectory: NULL])
    {
        // the folder exists, there might be drafts
        NSArray * files = [fileManager contentsOfDirectoryAtURL: draftsDirectoryURL
                                     includingPropertiesForKeys: nil
                                                        options: NSDirectoryEnumerationSkipsHiddenFiles
                                                          error: &error];
        if (nil == files)
        {
            NSLog(@"Error loading drafts from disk: %@, %@", error, [error localizedDescription]);
        }
        else
        {
            for (NSURL * aDraftURL in files)
            {
                // This is just a check for debugging purposes
                NSData * draftData = [NSData dataWithContentsOfURL: aDraftURL];
                if (draftData.length == 0)
                {
                    NSLog(@"WARNING: no file, or zero-size file at URL: %@", aDraftURL);
                }

                NSMutableDictionary * draftDict = [[NSMutableDictionary alloc] init];

                NSString * draftName = [[aDraftURL lastPathComponent]stringByDeletingPathExtension];
                // let's make sure we won't crash because we are inserting nil into a dictionary
                if (nil != draftName)
                {
                    draftDict[@"draftFilename"] = [[aDraftURL lastPathComponent]stringByDeletingPathExtension];
                }
                else
                {
                    NSLog(@"WARNING: no fileName without extension for draft at URL: %@", aDraftURL);
                }


                NSDate * creationDate = nil;
                [aDraftURL getResourceValue: &creationDate forKey:NSURLCreationDateKey error:&error];
                // let's make sure we won't crash because we are inserting nil into a dictionary
                if (nil != creationDate)
                {
                    draftDict[@"creationDate"] = creationDate;
                }
                else
                {
                    NSLog(@"WARNING: no creationdate found for file at URL: %@", aDraftURL);
                }

                // self.drafts will always return a fully initialized NSMutableArray, so we
                // can safely add an object at index 0
                [self.drafts insertObject: draftDict atIndex: 0];
            }
        }
    }
    else
    {
        NSLog(@"The drafts folder does not exist.");
    }

    NSLog(@"%@ stored drafts: %@", @([self.drafts count]), self.drafts);
}

@end

【讨论】:

  • 谢谢 - 感谢您抽出宝贵的时间来写这篇文章。我在我的项目中插入了这段代码并试了一下。它工作正常,并找到所有文件。但是,我的代码也找到了所有文件(正如我在问题中指出的那样)。问题仍然存在,不是我找不到草稿,而是 7 个 init 空 NSData 对象中的 5 个。
【解决方案2】:

我发现了问题所在。应用程序的文档目录在某些时候发生了变化,因此文件的位置也发生了变化。

文件保存在这里:

/var/mobile/Applications/09E7C349-6D03-4D2F-BE17-46C00B17C9F5/Documents/drafts/2014-08-13_12-57-57.m4a

稍后在这里:

/var/mobile/Applications/1A444A31-C29D-4B0F-8B47-A5B57D7F3281/Documents/drafts/2014-08-16_20-45-06.m4a

请注意,该应用的文件夹具有不同的令牌。所以文件在“那里”,但我猜不在那里。显然,当使用新的配置文件或应用商店有更新时,应用的目录可能会发生变化(请参阅this answer)。

所以这个故事的寓意是:不要将绝对路径保存为对文件的引用。

【讨论】:

  • 是的。这就是为什么你应该使用 NSFileManager。并且仅出于这个原因使用/存储相对于您的应用程序的路径(当您更新应用程序时,令牌也会更改)。所以最后,问题出在你形成 URL 的方式上。从 NSSearchPathForDirectoriesInDomains 上的文档中:(...)“您应该考虑使用 NSFileManager 方法...注意:此方法返回的目录可能不存在。此方法只是为您提供所请求目录的适当位置(... )"
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-25
  • 2016-09-19
  • 2019-09-24
  • 1970-01-01
  • 2018-05-30
  • 1970-01-01
  • 2011-09-26
相关资源
最近更新 更多