【发布时间】:2016-05-26 09:17:15
【问题描述】:
我正在尝试使用 POST 请求从服务器下载一个大文件。该文件作为 base64Encoded 数据接收。文件大小超过 400Mb。我使用的第一种方法是附加在 didReceiveData 中收到的数据,然后在 connectionDidFinishLoading 我用来解码数据并写入数据到文档目录中的文件。这种方法适用于小尺寸的文件。但由于文件大小非常大(400MB),它会崩溃。然后我使用 NSFileHandle 的方法在接收到数据时将文件分块写入。我使用 3MB 的块来写入数据。对于小于 3MB 的文件,接收到的数据直接从 base64 解码,文件创建成功。但是当文件大小大于 3MB 并且我尝试使用“initWithBase64EncodedData: Options”从 base64 解码块数据时,我得到的数据为零。想知道我在代码中做错了什么。
- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response
{
receivedData = [[NSMutableData alloc] init];
NSString* folderPath = [NSHomeDirectory() stringByAppendingPathComponent:@"/Documents/UserDocs"];
if(![[NSFileManager defaultManager] fileExistsAtPath:folderPath]) {
[[NSFileManager defaultManager] createDirectoryAtPath:folderPath withIntermediateDirectories:NO attributes:nil error:nil];
}
NSString *strFilePath = [folderPath stringByAppendingPathComponent:strFileName]; NSString *newFilePath = [NSString stringWithFormat:@"%@.%@", strFilePath, strFileExtension];
if(![[NSFileManager defaultManager] fileExistsAtPath:newFilePath]) {
[[NSFileManager defaultManager] createFileAtPath:newFilePath contents:nil attributes:nil];
}
self.fileHandle = [[NSFileHandle fileHandleForWritingAtPath:newFilePath] retain];
[self.fileHandle seekToFileOffset:0];
}
- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data
{
[receivedData appendData:data];
NSUInteger chunkSize = 300000;
if( receivedData.length > chunkSize && self.fileHandle!=nil) {
NSData *chunk = [receivedData subdataWithRange:NSMakeRange(0, chunkSize)];
NSData *writableData = [[NSData alloc] initWithBase64EncodedData:chunk options:NSDataBase64DecodingIgnoreUnknownCharacters];
[receivedData replaceBytesInRange:NSMakeRange(0, chunkSize) withBytes:NULL length:0];
[self.fileHandle seekToEndOfFile];
[self.fileHandle writeData:writableData];
[writableData release];
}
}
- (void)connectionDidFinishLoading:(NSURLConnection*)connection
{
if (receivedData)
{
NSData *writableData = [[NSData alloc] initWithBase64EncodedData:receivedData options:NSDataBase64DecodingIgnoreUnknownCharacters];
[receivedData release];
[self.fileHandle seekToEndOfFile];
[self.fileHandle writeData:writableData];
[writableData release];
NSLog(@"File Write Success!!");
}
}
【问题讨论】:
-
Base64 不是一对一的编码方案,是吗,所以您将获得当前 chunk 所需的前一个 chunk 中的数据。您应该研究使用某种形式的 base-64 流解码器的可能性,您可以在其中向其提供输入数据块并告诉它在哪里写入解码后的数据。
-
尝试使用 NSStream、数据文件流和动态解码/编码来制作一个二进制文件,让我知道是否可以使用该代码:)
-
您可以控制服务器吗?如果是这样,为什么不直接发送数据而不进行 base64 编码呢?例如,如果您需要发回大 blob 之外的其他数据,则可以使用多部分 MIME 响应。或者更好的是,首先提供元数据,然后提供一个 URL,您可以在该 URL 中通过第二个请求请求未编码的大型数据文件。
标签: ios objective-c nsurlconnection