iOS中的大型Base64上载

iOS中的大型Base64上载,ios,http,upload,base64,Ios,Http,Upload,Base64,说明: 我需要在HTTP POST参数中发送一个base 64编码的字符串,该参数表示要上载的文件 当前方法:我正在使用ASIFormDataRequest并将我的文件编码为base64字符串,如下所示: NSData *data = [[NSFileManager defaultManager] contentsAtPath:@"my path here"]; NSString *base64Data = [data encodeBase64ForData]; 然而,当上传大文件时,该应用程

说明: 我需要在HTTP POST参数中发送一个base 64编码的字符串,该参数表示要上载的文件

当前方法:我正在使用ASIFormDataRequest并将我的文件编码为base64字符串,如下所示:

NSData *data = [[NSFileManager defaultManager] contentsAtPath:@"my path here"];
NSString *base64Data = [data encodeBase64ForData];
然而,当上传大文件时,该应用程序内存不足,死去活来

建议的解决方案:现在有人知道我该怎么做了吗,比如说,从磁盘读取文件,将其分块转换为base64字符串,并将转换后的base64字符串附加到HTTP请求中的参数

有效地避免将整个文件读入内存的任何方法

任何意见都将不胜感激

我的http请求代码全文:

NSURL *url = [NSURL URLWithString:requestProgressURLString];
NSData *data = [[NSFileManager defaultManager] contentsAtPath:evidence.uri];
NSString *base64Data = [data encodeBase64ForData];
NSURL *fileURL = [[NSURL alloc] initWithString:evidence.uri];

request = [ASIFormDataRequest requestWithURL:url];

request.shouldAttemptPersistentConnection = false;
[request setShowAccurateProgress:YES];

[request setPostValue:accessToken forKey:@"AccessToken"];
[request setPostValue:[[fileURL path] lastPathComponent] forKey:@"Filename"];
[request setPostValue:evidence.name forKey:@"Title"];
[request setPostValue:base64Data forKey:@"FileData"]; //wants string value (base64 encoded)          
[request addRequestHeader:@"Content-Type" value:@"application/x-www-form-urlencoded"];
[request setTimeOutSeconds:60];
[request setUploadProgressDelegate:self];
[request setDownloadProgressDelegate:self];
[request setDelegate:self];
[request setDidFinishSelector:@selector(requestDone:)];
[request setDidFailSelector:@selector(requestWentWrong:)];

你需要分块读取文件,而不是一次性读取文件

您可以使用输入流来执行此操作 苹果有一些关于

基本上,您需要创建指向您的文件的NSInputStream,如示例所示

- (void)setUpStreamForFile:(NSString *)path {
    // iStream is NSInputStream instance variable
    iStream = [[NSInputStream alloc] initWithFileAtPath:path];
    [iStream setDelegate:self];
    [iStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
        forMode:NSDefaultRunLoopMode];
    [iStream open];
}
然后,您可以使用NSStreamDelegate方法读取数据块 -(void)流:(NSStream*)流句柄事件:(NSStreamEvent)事件代码

苹果再次给出了一个例子

- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {

    switch(eventCode) {
        case NSStreamEventHasBytesAvailable:
        {
            if(!_data) {
                _data = [[NSMutableData data] retain];
            }
            uint8_t buf[1024];
            unsigned int len = 0;
            len = [(NSInputStream *)stream read:buf maxLength:1024];
            if(len) {
                [_data appendBytes:(const void *)buf length:len];
                // bytesRead is an instance variable of type NSNumber.
                [bytesRead setIntValue:[bytesRead intValue]+len];

                // DO SOMETHING with DATA HERE

            } else {
                NSLog(@"no buffer!");
            }
            break;
        }
您选择的块大小需要在内存性能与网络性能之间取得平衡,因为HTTP头显然存在一些开销

您还可以通过直接发送NSData(从而节省base64开销)进一步优化此帖子


我将把这个问题分成两部分:

1。将大文件分块编码为Base64
2。上传该文件


1。将大文件分块编码到Base64:

查找将
NSData
实例编码为Base64的一些代码。然后使用一个
NSInputStream
读取数据块,对其进行编码,然后使用
NSOutputStream
写入临时文件。我发现了这个问题/答案:将块大小设为3的倍数,它应该可以工作。您可能希望将其移动到后台线程

重要提示:这将创建一个比原始文件大的临时文件。设备上必须有足够的空间用于那个时刻。开始上传后,您可以将其删除


2。上传该文件

看来你已经做到了。您可以使用与示例中完全相同的
ASIFormDataRequest
。由于它生成文件的私有副本(它生成多部分POST文件),因此您可以删除副本


如果您想通过并行化这些步骤来优化它,您需要找到另一种方法来上载多部分文件。

我从未见过chunking Base64转换器,但采用开源实现并将其转换为chunking Base64转换器应该不会太难。Base64并没有那么复杂。您也可以控制web服务器吗?也就是说,你能在那里修改代码吗?当你说大文件的时候?多大?100MB?500兆?1 GB?目前上传限制为100MB,但将来可能会增加。理想情况下,无论上传的大小,解决方案都应该有效,因为我相信这段代码将在更多的项目中使用。我现在正在研究streams…您的服务器支持多部分上传吗?如果您也控制服务器,base64将非常低效,最好避免。