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服务器
- 用Application Loader上传IPA
- Youtube APIauthentication – iPhone
- 错误ITMS-9000:“缺less代码签名权利。 在捆绑中找不到权利“ – 如何更改应用程序ID名称
- facebook ios sdk – 使用UIImage发送照片的麻烦
- 上传图像从iOS应用程序到PHP – 不能完全正确 – 我错过了什么?
- 通过stream式上传文件:显示错误日志“操作无法完成。 (kCFErrorDomainCFNetwork错误303.)“
- 为什么Xcode 4.3.2在归档时显示白色图标?
- 如何从iPhone上传video到服务器?
- iOS:当应用程序在后台时执行上传任务