我使用带有php的SAX Parser解析一个1.2GB的xml文件,结果写在一个txt文件中。几分钟后,我得到一个"在第x和34行没有记忆的错误。完成此操作后,文本文件输出仅为几KB(而预期的输出文件大小可能会超过几MB)并且存储的信息非常少。我使用xampp在带有i7处理器和18 GB RAM的Windows 7 64位系统上运行这个项目,但我也在32位系统上运行它,结果相同。我用这些命令修改了php.ini:
ini_set('max_execution_time', 72000);
ini_set('memory_limit','13056M');
ini_set('realpath_cache_size','13056000k');
ini_set('max_input_time','-1');
我应该在php.ini中修改一些内容吗?当代码没有找到要解析的过滤数据并且只读取" junk"这可能是某种缓冲区溢出。数据?这可能是由OS文件大小限制引起的错误吗?有没有人解决过类似的问题? 提前谢谢。
答案 0 :(得分:1)
问题可能是您用来解析xml文件的函数。解析具有错误函数的大型xml文件需要大量内存,因为xml文档是"后退"在返回结果之前在系统内存中。
我非常熟悉php的XMLReader
类来解析大型xml文件。
http://php.net/manual/en/class.xmlreader.php
请不要增加memory_limit
来解决此问题,我认为这是解决错误的错误方法。
肯定你没有向我们展示你的代码的整个实现,问题也可以通过你在php中进行进一步处理数据的方式找到(制作一个大型阵列,不要{t {1}}变量)很难分辨。
答案 1 :(得分:1)
我遇到了同样的问题,到目前为止我的调查指出了使用的libxml2版本。高于2.7.6的版本似乎对内存使用有限制,除非您明确允许它使用超过硬编码限制(LIBXML_PARSEHUGE)。
查看http://php.net/manual/en/libxml.constants.php了解详情。
不幸的是,我还没有找到解决问题的方法,即在PHP中使用XML Parser函数时如何设置此选项。我猜xml_parser_set_option会是正确的地方吗?
目前似乎唯一的选择是更新代码以使用XMLReader。此扩展在open函数中有option参数,您可以在其中提供libxml选项常量。
更新!
查看xml扩展的源代码,我发现xml_parse函数正在使用不带选项的libxml函数xmlParseChunk。我能够通过减少块大小而不提供此选项来使其工作(xml_parse失败,并且#39;没有内存'当块大小超过9.5MB时)。也许你可以试试这个:
while ($data = fread($fp, 1024*1024)) {
xml_parse($parser, $data, feof($fp)) or
die(sprintf('XML ERROR: %s at line %d',
xml_error_string(xml_get_error_code($parser)),
xml_get_current_line_number($parser)));
}
答案 2 :(得分:0)
我有一个数组,但我不认为它变得太大了。它必不可少我不清楚那个数组。没有会话只使用简单的字符串变量。
我正在解析从官方来源下载的dblp.xml文件,因此很少有机会形成xml(也包含有效的dtd)。
我不想发布代码因为它有点大但是在这里:
ini_set('max_execution_time', 72000);
$professors = array();
$parser = xml_parser_create();
xml_set_element_handler($parser, 'start_element', 'end_element');
xml_set_character_data_handler($parser, 'character_data');
function start_element($parser, $element_name, $element_attrs) {
global $interest;
global $author_id;
global $id;
global $author;
global $no_url;
global $url;
global $professors;
global $counter;
global $author_name;
switch ($element_name) {
case 'WWW':
$counter = 0;
$duplicate = false;
$author_id = end($element_attrs);
if (substr($author_id, 0, 9) === 'homepages') {
for ($i = 0; $i < count($professors); $i++) {
if ($author_id === $professors[$i]) {
$duplicate = true;
}
}
if ($duplicate) {
$id = false;
$interest = false;
}
else {
array_push($professors, $author_id);
$id = true;
$interest = true;
}
}
break;
case 'AUTHOR':
$author_name = "";
$author = true;
$no_url = true;
break;
case 'URL':
$url = true;
$no_url = false;
break;
}
}
function character_data($parser, $data) {
$fp1 = fopen("Authors.txt","a+");
global $interest;
global $author_id;
global $id;
global $author;
global $no_url;
global $url;
global $counter;
global $author_name;
if ($interest && $id) {
if ($no_url) {
fwrite($fp1,"*" . "\r\n");
fwrite($fp1,$author_id);
}
else {
fwrite($fp1,$author_id);
}
$id = false;
}
if ($interest && $author) {
$author_name .= $data;
}
if ($interest && $url) {
$url_name = $data;
fwrite($fp1,"*" . $url_name . "\r\n");
}
}
function end_element($parser, $element_name) {
global $interest;
global $author_id;
global $id;
global $author;
global $url;
global $author_name;
$fp1 = fopen("Authors.txt","a+");
switch ($element_name) {
case 'WWW':
$interest = false;
break;
case 'AUTHOR':
if ($interest && $author) {
fwrite($fp1,"*" . $author_name);
$author = false;
}
break;
case 'URL':
$url = false;
break;
case 'DBLP':
die(sprintf('End of XML'));
xml_parser_free($parser);
break;
}
}
$fp = fopen('dblp.xml', 'r')
or die ("Cannot open dblp.xml!");
while ($data = fread($fp, 100000000)) { //i give such a huge number to read each time to cover the case of a large line in the xml.i get the same no memory at line error though with the default 4096 value as well
xml_parse($parser, $data) or
die(sprintf('XML ERROR: %s at line %d',
xml_error_string(xml_get_error_code($parser)),
xml_get_current_line_number($parser)));
}
xml_parser_free($parser);