早上好, 我正在开发一个上传一些文件的应用程序;没有真正的问题,但只有一个大问题:如果我尝试上传1GB的文件,它会分配1GB的内存,你可以理解这不是一件好事。
这是我的代码:我将数据分配为NSData,然后使用NSMutableURLRequest + NSURLConnection上传它们;我的问题是:有没有办法做到这一点,而无需分配整个内存?我搜索过了,但我一无所获......
_uploadDataFile是之前分配的NSData子类实例。
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://my.server/page"]
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:60.0] autorelease];
NSData *dataFile;
if (_uploadDataFile == nil) {
NSError *error = nil;
dataFile = [[[NSData alloc] initWithContentsOfFile:@"pathToFile" options:NSDataReadingUncached error:&error] autorelease];
if (error) {
NSLog(@"Error %i: %@", [error code], [error localizedDescription]);
[self fermaUpload]; //Stop Upload
return;
}
}
else
dataFile = [_uploadDataFile file];
NSMutableDictionary *dictPost = [[[NSMutableDictionary alloc] init] autorelease];
[dictPost setValue:dataFile forKey:@"uploads[]"];
NSData *mutData = [self dataForPOSTWithDictionary:dictPost boundary:@"0194784892923" nomeFile:[@"pathToFile" lastPathComponent]];
NSString *postLength = [NSString stringWithFormat:@"%d", [mutData length]];
[request setHTTPMethod:@"POST"];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
[request setValue:@"multipart/form-data; boundary=0194784892923" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:mutData];
[request setHTTPShouldHandleCookies:YES];
theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
以及如何 - (NSData *)dataForPOSTWithDictionary:boundary:nomeFile:方法如下:
- (NSData *)dataForPOSTWithDictionary:(NSDictionary *)aDictionary boundary:(NSString *)aBoundary nomeFile:(NSString *)nomeFile {
NSArray *myDictKeys = [aDictionary allKeys];
NSMutableData *myData = [NSMutableData dataWithCapacity:1];
NSString *myBoundary = [NSString stringWithFormat:@"--%@\r\n", aBoundary];
for(int i = 0;i < [myDictKeys count];i++) {
id myValue = [aDictionary valueForKey:[myDictKeys objectAtIndex:i]];
[myData appendData:[myBoundary dataUsingEncoding:NSUTF8StringEncoding]];
//if ([myValue class] == [NSString class]) {
if ([myValue isKindOfClass:[NSString class]]) {
[myData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", [myDictKeys objectAtIndex:i]] dataUsingEncoding:NSUTF8StringEncoding]];
[myData appendData:[[NSString stringWithFormat:@"%@", myValue] dataUsingEncoding:NSUTF8StringEncoding]];
} else if(([myValue isKindOfClass:[NSURL class]]) && ([myValue isFileURL])) {
[myData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", [myDictKeys objectAtIndex:i], [[myValue path] lastPathComponent]] dataUsingEncoding:NSUTF8StringEncoding]];
[myData appendData:[[NSString stringWithFormat:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[myData appendData:[NSData dataWithContentsOfFile:[myValue path]]];
} else if(([myValue isKindOfClass:[NSData class]])) {
[myData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", [myDictKeys objectAtIndex:i], nomeFile] dataUsingEncoding:NSUTF8StringEncoding]];
[myData appendData:[[NSString stringWithFormat:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[myData appendData:myValue];
} // eof if()
[myData appendData:[[NSString stringWithString:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
} // eof for()
[myData appendData:[[NSString stringWithFormat:@"--%@--\r\n", aBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
return myData; } // eof dataForPOSTWithDictionary:boundary:
谢谢你,对不起我的英语。
答案 0 :(得分:3)
一个最有趣的问题!有两种方法可以将身体数据输入NSURLConnection/Request
:
NSData
NSInputStream
不幸的是,既不想开箱即用,也不想上传文件+某些表单数据。理想情况下,您可以将NSInputStream
子类化,以根据需要提供格式化的数据。但是,我上次检查时,NSURLConnection
无法处理此类子类。相反,做一些像:
CFStreamCreateBoundPair()
创建一对流。这会返回CFWriteStream
和CFReadStream
,它们分别免费桥接到NSOutputStream
和NSInputStream
-setHTTPBodyStream:
现在应该定期调用输出流的委托,请求数据。您需要输入POST数据,然后输入大量文件数据。因此,整个文件永远不会完全在内存中。