1

我已经看到这个问题已经存在于 stackoverflow 中,但我的问题没有答案。

我有从另一台服务器下载的许多文件的目录,我不知道有多少文件以及尺寸可以是 1GB 我认为或 100Mb 取决于外部服务器。

现在我已经这样做了:

    ini_set("memory_limit","10000M");
    $directory = "xml_uploads/hotel/";
    $xml_files = glob($directory . "*.xml");       
    foreach($xml_files as $file)
    {
        $content = file_get_contents($file, true);
        $xml = new DOMDocument();
        $xml->loadXML($content);
        if($xml){
           //parse xml and save inside database
        } 
     }

我不知道是否是在 memory_limit 中插入这样的大数字的更好方法,因为我不知道 rela 大小和如果太大我不想停止我的服务器。是否存在另一种解析目录中所有 xml 文件的方法?

谢谢

4

3 回答 3

1

XML 解析

目前您正在使用DOMDocument组合file_get_contents- 这意味着您必须首先将巨大的 XML 文件加载到内存中,并且每当文件大于可用内存时,您总是会达到限制 - 使用下面的解决方案,这不是问题。

如果您担心 XML 解析代码的内存使用情况,您应该使用pull解析器 - 它是一种 XML 解析器,它不会将所有内容加载到内存中,但允许您一次仅对一个实体进行操作 - 这样内存使用量很小。在 PHP 中,您可以使用XML Reader

$xml = new XMLReader();
$xml->open("config.xml");

while ($xml->read()) {
    switch ($xml->name) {
        case "myelem":
             ...
    }
}

巨大的目录树遍历

当然!有一个DirectoryIteratorRecursiveDirectoryIterator

用法非常相似:

foreach(new DirectoryIterator($directory) as $fileInfo)
{
    if($fileInfo->getExtension() !== 'xml') continue;
    $content = file_get_contents($fileInfo->getPathname(), true);
    ...
}

另外,如果你有一个嵌套的目录结构,你可以使用另一个:

foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory)) as $fileInfo)
{
    if($fileInfo->getExtension() !== 'xml') continue;
    $content = file_get_contents($fileInfo->getPathname(), true);
    ...
}

请注意,由于这个迭代器是递归的,我们必须用RecursiveIteratorIterator;包装它。

从 PHP 5 开始,这两个都可用(你真的不应该使用低于它的任何东西)

于 2013-09-27T08:05:47.457 回答
0

使用下面的代码,您可以获得要上传的文件的大小(在上传之前,您将使用 js 获得文件的大小)然后您可以使用 ajax 上传文件并相应地调整内存大小。

如果不需要,请删除不需要的代码

<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<title>Show File Data</title>
<style type='text/css'>
body {
font-family: sans-serif;
}
</style>
<script type='text/javascript'>
function showFileSize() {
var input, file;

// (Can't use `typeof FileReader === "function"` because apparently
// it comes back as "object" on some browsers. So just see if it's there
// at all.)
if (!window.FileReader) {
bodyAppend("p", "The file API isn't supported on this browser yet.");
return;
}

input = document.getElementById('fileinput');
if (!input) {
bodyAppend("p", "Um, couldn't find the fileinput element.");
}
else if (!input.files) {
bodyAppend("p", "This browser doesn't seem to support the `files` property of file inputs.");
}
else if (!input.files[0]) {
bodyAppend("p", "Please select a file before clicking 'Load'");
}
else {
file = input.files[0];
alert("File " + file.name + " is " + file.size + " bytes in size");

//bodyAppend("p", "File " + file.name + " is " + file.size + " bytes in size");
}
}

function bodyAppend(tagName, innerHTML) {
var elm;

elm = document.createElement(tagName);
elm.innerHTML = innerHTML;
document.body.appendChild(elm);
}
</script>
</head>
<body>
<form action='#' onSubmit="return false;">
<input type='file' id='fileinput'>
<input type='button' id='btnLoad' value='Load' onclick='showFileSize();'>
</form>
</body>
</html>
于 2013-09-27T08:18:25.940 回答
0

亚当的回答已经指出了好的课程,我还有一些提示给你:

当您执行大型文件和耗时/内存消耗的事情时,您无法从浏览器中点击该脚本。服务器大多具有有限的 KeepAlive 和 Timeout,即使有 1 TB 内存也会杀死你的脚本。

给你的脚本一个 shebang,使其可执行(chmod +x 或 chmod 700)并从控制台(http://www.php.net/manual/en/features.commandline.usage.php)点击它。

#!/usr/bin/php
<?php
// set memory limit here..
// set time limit:
set_time_limit(0)

// maybe enable garbage collector here
// http://php.net/manual/en/features.gc.php

另请参阅此答案某人有类似问题:

php exec() - max_execution_time 和致命错误

于 2013-09-27T08:23:53.057 回答