iOS中大量的Base64上传

说明:我需要在HTTP POST参数中发送一个base 64编码的string,表示要上传的文件。

当前的方法:我正在使用一个ASIFormDataRequest并将我的文件编码到一个base64string,如下所示:

NSData *data = [[NSFileManager defaultManager] contentsAtPath:@"my path here"]; NSString *base64Data = [data encodeBase64ForData]; 

然而,当上传大文件的应用程序耗尽内存,并死亡一个可怕的死亡!

build议的解决scheme:现在有谁可以从磁盘读取文件,将其转换为base64string,并将转换后的base64string附加到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:)]; 

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

1.将大文件以大块的forms编码到Base64
2.上传该文件


1.将大文件以大块的forms编码到Base64中:

find一些编码NSData实例到Base64的代码。 然后使用一个NSInputStream以块读取数据,对其进行编码并使用NSOutputStream写入临时文件。 我发现这个问题/答案: 是否有可能base64编码一个文件块? 使块大小为3的倍数,它应该工作。 你可能想把它移到后台线程。

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


2.上传该文件

看来你已经完成了。 你可以像你的例子那样使用ASIFormDataRequest 。 而且,由于它使文件的私人副本(它构build了多部分POST文件),您可以删除您的副本。

如果要通过并行化这些步骤来优化它,则需要find另一种上传多部分文件的方法。

不要一次阅读文件,你需要阅读大块

你可以使用inputstream来做到这一点苹果有一些信息在这里

基本上你需要像在这个例子中那样创build一个指向你的文件的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)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode

苹果再次举例说明这一点

 - (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; } 

你select的块的大小需要是内存性能与networking性能的平衡,因为HTTP标头显然有一些开销

你也可以通过直接发送你的NSData进一步优化(因此保存base64的开销)检查这个post

file upload到iPhone编程中的HTTP服务器