使用iOS Dropbox SDK进行核心数据的分块上传

时间:2012-12-08 10:31:06

标签: objective-c ios dropbox

我有一个iOS应用程序,它使用Core Data进行持久数据存储。我将Dropbox集成为用户执行持久存储文件(appname.sqlite)备份的一种方式。

UIButton调用一个方法来查看Dropbox上是否已存在文件:

            if([[DBSession sharedSession]isLinked])
            {
               NSString *folderName = [[self.dateFormatter stringFromDate:[NSDate date]] stringByReplacingOccurrencesOfString:@"/" withString:@"-"];
               NSString *destinationPath = [NSString stringWithFormat:@"/GradeBook Pro/Backup/%@/",folderName];
               self.metadataIndex = METADATA_REQUEST_BACKUP;
               [self.restClient loadMetadata:destinationPath];
            }

loadedMetadata委托方法使用现有文件的rev号(如果存在)启动上载。

-(void) restClient:(DBRestClient *)client loadedMetadata:(DBMetadata *)metadata
{
            SAVE_CORE_DATA;
            NSString *folderName = [[self.dateFormatter stringFromDate:[NSDate date]] stringByReplacingOccurrencesOfString:@"/" withString:@"-"];
            NSString *documentsDirectory = DOCUMENTS_DIRECTORY;
            NSString *sourcePath = [NSString stringWithFormat:@"%@/GradeBookPro.sqlite", documentsDirectory];
            NSString *destinationPath = [NSString stringWithFormat:@"/GradeBook Pro/Backup/%@/",folderName];
            [self.restClient uploadFile:@"GradeBookPro.sqlite" toPath:destinationPath withParentRev:[[metadata.contents lastObject]rev] fromPath:sourcePath];               
}

这适用于完美网络连接上相当小的文件或大文件,但上传过程中的任何小错误都会取消整个过程。我想切换到使用分块上传方法,但我不知道如何实际执行.sqlite文件的“分块”。

我似乎找不到任何使用我可以学习的分块上传的示例应用程序,文档只是说以块的形式提供文件。

所以,我的问题是:

  1. 分块上传是否正确解决了用户在可能不稳定的网络连接上上传大文件的问题?

  2. 您能指点一下“分块”文件的示例代码/应用/文档吗?我对Dropbox SDK非常满意。

  3. 谢谢!

1 个答案:

答案 0 :(得分:15)

我将自己回答这个问题,以防其他人遇到同样的问题。

事实证明,我这样做比现在更困难。 Dropbox SDK处理文件分块,所以我只需要启动传输并对委托调用做出反应。使用的方法是:

要发送文件块 - 对于第一个块,使用nil作为uploadId,使用0作为偏移量:

- (void)uploadFileChunk:(NSString *)uploadId offset:(unsigned long long)offset fromPath:(NSString *)localPath;

发送最后一个块后,使用此方法提交上传:

- (void)uploadFile:(NSString *)filename toPath:(NSString *)parentFolder withParentRev:(NSString *)parentRev fromUploadId:(NSString *)uploadId;

我按如下方式处理了委托方法:

    - (void)restClient:(DBRestClient *)client uploadedFileChunk:(NSString *)uploadId newOffset:(unsigned long long)offset fromFile:(NSString *)localPath expires:(NSDate *)expiresDate
    {
        unsigned long long fileSize = [[[NSFileManager defaultManager]attributesOfItemAtPath:[FileHelper localDatabaseFilePath] error:nil]fileSize];

        if (offset >= fileSize)
        {
            //Upload complete, commit the file.
            [self.restClient uploadFile:DATABASE_FILENAME toPath:[FileHelper remoteDatabaseDirectory] withParentRev:self.databaseRemoteRevision fromUploadId:uploadId];
        }
        else
        {
            //Send the next chunk and update the progress HUD.
            self.progressHUD.progress = (float)((float)offset / (float)fileSize);
            [self.restClient uploadFileChunk:uploadId offset:offset fromPath:[FileHelper localDatabaseFilePath]];
        }
    }

由于我试图解决的主要问题是处理不良连接,我实现了失败的块上传的委托方法:

- (void)restClient:(DBRestClient *)client uploadFileChunkFailedWithError:(NSError *)error
{
    if (error != nil && (self.uploadErrorCount < DROPBOX_MAX_UPLOAD_FAILURES))
    {
        self.uploadErrorCount++;
        NSString* uploadId = [error.userInfo objectForKey:@"upload_id"];
        unsigned long long offset = [[error.userInfo objectForKey:@"offset"]unsignedLongLongValue];
        [self.restClient uploadFileChunk:uploadId offset:offset fromPath:[FileHelper localDatabaseFilePath]];
    }
    else
    {
      //show an error message and cancel the process
    }
}