php - 用 php 读取大的 json 文件
问题描述
我在某处读过我应该使用该库salsify/jsonstreamingparser
打开一个大的 json 文件,但它给了我与以下相同的错误json_decode
:
PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 20480 bytes) in /data/www/default/database/vendor/salsify/json-streaming-parser/src/Listener/InMemoryListener.php on line 92
我必须在 php 中执行此操作,因为我使用的是没有 python 的免费托管。
基本上我想要做的是下载一个大的 json 文件解压缩并处理内容。我不知道为什么在 php 中我一整天都无法做到,但在 python 中我在 5 分钟内做到了:
import os
import json
import urllib
import zipfile
json_file = 'AllSets-x.json'
zip_file = json_file + '.zip'
urllib.urlretrieve ("https://mtgjson.com/json/" + zip_file, zip_file)
dir_path = os.path.dirname(os.path.realpath(__file__))
zip_ref = zipfile.ZipFile(dir_path + "/" + zip_file, 'r')
zip_ref.extractall(dir_path)
zip_ref.close()
json_data = json.load(open(json_file, 'r'))
print json_data.keys()[0]
这就是我在 php 中所拥有的:
<?php
require_once __DIR__ . '/vendor/autoload.php';
include "../credentials.php";
error_reporting(E_ALL); # Reports all errors
ini_set('display_errors','Off'); # Do not display errors for the end-users (security issue)
ini_set('error_log','/tmp/php-errors.log'); # Set a logging file
// Override the default error handler behavior
set_exception_handler(function($exception) {
$logger->error($exception);
echo "Something went wrong!";
});
$logger = new Monolog\Logger('channel-name');
$logger->pushHandler(new Monolog\Handler\StreamHandler('/tmp/php-errors.log', Monolog\Logger::DEBUG));
$logger->info("Parsing json file");
$listener = new \JsonStreamingParser\Listener\InMemoryListener();
$json_file = __DIR__ . "/AllSets-x.json";
$stream = fopen($json_file, 'r');
try {
$parser = new \JsonStreamingParser\Parser($stream, $listener);
$parser->parse();
fclose($json_file);
} catch (Exception $e) {
fclose($json_file);
throw $e;
}
$logger->info("Json file parsed");
$json_data = $listener->getJson();
$logger->info("Displaying json data");
var_dump($json_data);
解决方案
使用 InMemoryListener 肯定会破坏流解析器的目的。这只会将所有内容解压缩到内存中(在内存方面可能比 plain 更糟糕json_decode
)。
如果您想在此类约束下工作,则需要单独捕获每个 JSON 对象块。
SimpleObjectQueueListener可能符合要求。如果特定的 JSON 有一堆[{…}, {…}, {…}]
对象要处理:
$listener = new \JsonStreamingParser\Listener\SimpleObjectQueueListener("print_r", 0);
// would just print out each object block from the JSON stream
显然你会使用像“ process_my_json_blobs
”这样的回调。(或者[$pdo, "execute"]
可能是一个准备好的回调。)
顺便说一句,读取整个 JSON 输入只适用于本地 Python,因为通常没有memory_limit
常见的 PHP 设置。(Python 充其量依赖于系统ulimit
。)
推荐阅读
- node.js - 如何在 Google App Engine 上修复 CORS Node.js
- templates - 如何显示产品模板中的商店字段?
- sql - SQL将字符串转换为十进制,其中最后一个字段是负标识符
- angular - 将引导程序和 jQuery 添加到 Angular 8
- html - html:删除有序列表和前一行之间的空格
- java - 如何添加因查询参数不同的多个 RestController 端点?
- python - 在 UI PyQt5 中更新时钟和文本
- omnet++ - 即使我没有实现任何 BSM 发送,为什么 RSU 在收到预定的自消息后仍开始向节点发送 BSM 消息
- scala - 错误:org.apache.spark.sql.AnalysisException:无法推断 CSV 的架构
- drools - 如何备份和访问 jbpm 7.3 maven artifactory 和 git 存储库