我正在寻找有关如何改进使用base64编码解码40 + MB NSString并将其保存到文件的过程的想法,同时能够使进程适应iPad 1的256 MB RAM
我从NSXMLParser获取NSString:
id pointerToString;
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if ([currentElement isEqualToString:@"myElement"])
{
pointerToString = [string retain];
}
}
然后我在回调中使用pointerToString:
[handler performSelector: action withObject: pointerToString];
在回调中(id值为pointerToString)。我使用pointerToString初始化NSData,同时使用base64编码对其进行解码。
^(id value)
{
if ( [[value class] isSubclassOfClass:[NSString class]] )
{
NSData *data = [NSData dataFromBase64String:value];
[data writeToFile:file.path atomically:YES];
}
}
当NSData调用之后或期间内存分配达到130MB左右时,iPad 1设备内存不足并被iOS杀死。
我已经确定,为了以这种方式处理40 + MB NSString,我需要大约180 + MB的RAM(这是iPad 2& 3上的最大内存分配,这个过程有效,因为更多RAM)
任何想法/提示?
谢谢
答案 0 :(得分:2)
修改强>:
当处理这个大小的文件时,你可能不希望一次在内存中加载整个多兆字节文件,既不是巨大的输入文件也不是几乎同样巨大的输出文件。您应该以流式方式解析此问题,在进行时解码foundCharacters
中的数据,而不是在内存中保留任何重要部分。
但是,传统技术可能会在整个过程的三个阶段保存整个XML文件内存:
从服务器下载XML文件时;
当XML解析器解析该文件时;以及
当你对文件进行Base64解码时。
诀窍是采用流技术,一次完成这三个进程,用于单个大型XML文件的小块。最重要的是,当您下载整个50mb文件时,抓取几个kb,解析XML,如果您正在解析Base64编码的字段,请执行Base64-decode为几kb,然后继续下一步大块数据。
有关此示例(至少是流式XML下载和解析,不包括Base64解码),请参阅Apple的XMLPerformance sample project。您将看到它将演示两个XML解析器,我们都熟悉的NSXMLParser
,以及不太熟悉的LibXML
解析器。 NSXMLParser
的问题是,留给它自己的设备,即使你使用initWithContentsOfURL
,它也会在开始解析之前将整个XML文件加载到内存中。
在我之前的回答中,我错误地声称通过使用initWithContentsOfURL
,NSXMLParser
会在下载时将精美的小数据包解析为URL的内容。 foundCharacters
协议的NSXMLParserDelegate
方法似乎与NSURLConnectionDelegate
方法didReceiveData
类似,我确信NSXMLParser
将像处理流一样处理流NSURLConnection
确实如此,即在下载过程中返回信息。可悲的是,它没有。
通过使用LibXML
,与Apple XMLPerformance示例项目一样,您实际上可以使用流的NSURLConnection
功能,从而动态解析XML。
我创建了一点test project,但我可能会建议您详细介绍Apple的XMLPerformance示例项目。但是在我的实验中,一个56mb的XML文件在通过NSXMLParser
进行解析和转换时消耗超过100mb,但在使用LibXML2
时只消耗了2mb。
在您的评论中,您描述了将Base64编码数据下载到文件然后解码的愿望。这种方法效率似乎低得多,但肯定可行。顺便说一句,在初始下载时,你有相同的内存问题(我在上面解决)。我强烈建议您确保初始下载Base64编码的数据并不像大多数例程那样轻松地将其加载到RAM中。假设您正在使用NSURLConnection
,您希望在收到NSOutputStream
中的数据时将数据写入didReceiveData
,而不是将其保存在RAM中。
请参阅Apple AdvancedURLConnections example的AdvancedGetController.m中的didReceiveResponse
,了解如何在收到文件时编写文件,而不是将文件添加到NSMutableData
的典型模式(因为大多数这些例程只是假设你正在处理一个合理大小的文件)。 (忽略AdvancedURLConnections示例中关于身份验证等的所有内容,但要集中精力了解它如何写入NSOutputStream
。这种技术将解决此处列出的三个问题中的第一个问题。回答,但不是后两者。为此,您必须考虑使用Apple的XMLPerformance示例项目或其他类似技术中所示的LibXML2
。
答案 1 :(得分:0)
方法
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
可能不会立即收到所有数据。 Doc说的是
“由解析器对象发送,为其委托提供表示当前元素的全部或部分字符的字符串。”
所以它被多次调用。 看起来你正试图一次写完整个字符串(对不起,如果我错了)。 因此,您可以通过执行以下操作将收到的数据附加到文件中:
您可以使用
的组合-writeData:
和
-seekToEndOfFile
NSFileHandle类中用于将NSData写入文件末尾的方法。
但请小心使用base64编码进行部分数据接收!