PHP 處理 JSON 大檔案,如果直接將整個檔案讀入記憶體,很容易遇到 Allowed memory exhausted 問題。除了解決網站伺服器遇到 Allowed memory exhausted 問題提到使用 jq 將大檔案切割成小檔案的方法、或依照檔案內容結構,逐行使用 PHP Generator (產生器) 處理。也可以使用 JSON Streaming Parser 直接處理。
![]() |
Purple PHP Women elephpant by Philip Sharp 使用創用 CC by-sa 授權 |
問題狀況
JSON 檔案約 250 MB,使用 json_decode 函數處理,遭遇記憶體耗盡的錯誤訊息
PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 20480 bytes)
問題解決
方法 1: 使用 jq - 處理 JSON 檔案的命令列工具
步驟 1: 安裝 jq
前往 jq 網站,根據作業系統版本,安裝對應的 jq。支援的作業系統有 Windows, Linux 與 OSX。根據個人經驗,Windows 版本 jq 建議透過 Cygwin 安裝 jq package。
步驟 2: 瞭解 JSON 內容結構
檔案太大時無法用一般文字編輯器打開。可以透過指令看部分檔案內容,例如逐頁看檔案內容
cat 檔名 | more
cat example.json | more
按 space 按鍵換頁,再按 q 就可以離開逐頁觀看模式
步驟 3: 依照 JSON 內容結構,決定處理方式
格式 I 完整的 JSON 格式
例如:projects 下有上千多筆的專案資料,example.json 檔案內容像:
{
"projects": [
{
"id": 1,
"name": "編號1專案"
},
{
"id": 2,
"name": "編號2專案"
}
]
}
請前往 解決網站伺服器遇到 Allowed memory exhausted 問題,了解將大檔案切割成小檔案的方法
步驟 3-1: 計算記錄筆數
jq '結構樹 | length' 檔名
jq '.projects | length' example.json
步驟 3-2: 預覽第一筆記錄
第一筆從 0 開始,結構樹語法需要標記 [0]
jq '結構樹' 檔名
jq '.projects[0]' example.json
範例檔案的結果是
{
"id": 1,
"name": "編號1產品"
}
步驟 3-3: 逐筆拆解紀錄,另存檔案
jq '結構樹' 檔名 > 輸出檔名
jq '.projects[0]' example.json > 0.json
jq '. projects[1]' example.json > 1.json
jq '. projects[2]' example.json > 2.json
因為檔案變小,後續就很容易解析小檔案內容。
格式 II 每行一筆 JSON 格式
例如:每行以 { 符號開始、} 符號結束。檔案內容看起來像:
{"id":1, "name":"編號1專案"}
{"id":2, "name":"編號2專案"}
步驟 3-1: 計算記錄筆數
wc -l 檔名
wc -l example.json
步驟 3-2: 預覽第一筆記錄
head -n 1 檔名 | jq .
head -n 1 example.json | jq .
上方指令先使用 head 指令,輸出第一行的檔案內容。再使用 | 符號 (pipe),當作 jq 的輸入資料,顯示比較好閱讀的 JSON 結構
使用 PHP Generator (產生器) 逐行讀取檔案內容即可。
方法 2: 使用 JSON Streaming Parser
步驟 1: 安裝 sergiorodenas/stream-parser 套件
composer require rodenastyle/stream-parser
步驟 2: 解析 JSON 內容
require_once __DIR__ . '/vendor/autoload.php';
use Rodenastyle\StreamParser\StreamParser;
use Tightenco\Collect\Support\Collection;
StreamParser::json($file_path)->each(function(Collection $row){
var_dump($row, true);
});
參考資料
- jq Manual (development version)
- StarTutorial: Php Generator Reading File Content
- php - 'safe' json_decode( ,,, ) to prevent exhausting memory - Stack Overflow 提到將檔案變小以及如何觀察記憶體變化
- Very easy to use and memory efficient drop-in replacement for inefficient iteration of big JSON...
- JSON Streaming Parser for PHP
- php - How to properly iterate through a big json file - Stack Overflow
- [扩展推荐] PHP 7 stream-parser 支持多格式的文件流解析器(超大文件 xml/JSON/CSV 读取解析的方案) | Laravel优质外文翻译 | Laravel China 社区
- JSON streaming - Wikipedia
- Pipe, Grep and Sort Command in Linux/Unix with Examples
JSON Streaming Parser
- sergiorodenas/stream-parser: ⚡ PHP7 / Laravel Multi-format Streaming Parser
- pcrov/JsonReader: A JSON pull parser for PHP
- salsify/jsonstreamingparser: A JSON streaming parser implementation in PHP
無效的嘗試
% jq --compact-output . test.json
留言
張貼留言