4 回答

TA貢獻1844條經(jīng)驗 獲得超8個贊
假設(shè)您的數(shù)據(jù)相當(dāng)對稱,最性能友好的選項就是簡單地array_chunk()
將數(shù)組切割成塊,當(dāng)json_encode
d 時,這些塊將大約是預(yù)期的大小。讓我們看一下數(shù)組中的樣本:
string(58)?"{"category":"1795","email":null,"level":1,"name":"BARFOO"}"
這里的“名稱”似乎是唯一可能變化更大的一個。我們將其平均為 12 個字符,每個項目的字符串長度為 64 字節(jié)。然后,您可以將其中的 78125 個放入 5MB 中。為了將其保持在標(biāo)記之下,我們將其設(shè)置為 75000。然后,$chunks = array_chunk($data, 75000)
將為您提供 X 個大約或略低于 5MB 標(biāo)記的塊。
現(xiàn)在,如果您想要更精確,并且尺寸確實很重要......我們可以:
$size = 0; // size counter
$chunkno = 1; // chunk number
$maxbytes = 50000; // 50000-byte chunks
$chunks = []; // for array chunks
foreach($data as $set) {
? ? // if over the limit, move on to next chunk
? ? if ($size > $maxbytes) {?
? ? ? ? $size = 0;
? ? ? ? $chunkno++;
? ? }
? ? $size += strlen(json_encode($set)) + 1; // add a comma's length!
? ? $chunks[$chunkno][] = $set;
}
// unset($data); // in case you have memory concerns
顯然,我們在這里使用 json_encode 執(zhí)行雙重任務(wù),但塊大小不會受到源數(shù)據(jù)差異的影響。我針對 50000 字節(jié)的塊運行了上面的測試腳本,您需要將其5000000用于您的用例。我生成的虛擬數(shù)據(jù)最多分為整齊的 50K 塊。+/- 一組的大小,加上最后一個文件中的剩余部分。
在思考這個問題時,我也考慮過這樣做strlen(implode(,但考慮到 PHP 的總體性能很好json_encode,為了獲得精確的 JSON 字符串大小而進行權(quán)衡,不應(yīng)該有太多的損失。
無論如何,一旦塊準(zhǔn)備好了,我們需要做的就是把它們寫下來:
foreach($chunks as $n => $chunk) {
? ? $json = json_encode($chunk);
? ? file_put_contents("tmp/chunk_{$n}.json", $json);
}
...或者匹配您的塊命名和目錄架構(gòu)。
也許有更聰明的方法可以做到這一點。也就是說,據(jù)我所知,核心 PHP 中沒有任何內(nèi)容可以開箱即用地執(zhí)行此類操作(即使對于普通數(shù)組也是如此),并且上述操作應(yīng)該執(zhí)行得相當(dāng)好。請記住有足夠的可用內(nèi)存。:)
PS 在計算大小時,我們?yōu)槊總€項目添加 +1,代表{},{},{},或?qū)ο蠓指舴?。嚴格來說,您還需要在總計中添加 +2,因為它將是[{},{},{}],而我們只將每個數(shù)組項的長度作為單獨的 JSON 對象進行計算。對于其他數(shù)據(jù)結(jié)構(gòu),您的補償里程可能會有所不同。
優(yōu)化更新:如果您選擇“精確大小”方法并希望優(yōu)化內(nèi)存使用,最好將 JSON 提交集成到分塊循環(huán)中。(感謝@NigelRen的建議。)如下(其他初始變量如前):
$chunk = [];
foreach($data as $n => $set) {
? ? if ($size > $maxbytes) {
? ? ? ? file_put_contents("tmp/chunk_{$chunkno}.json", json_encode($chunk));
? ? ? ? $chunk = [];
? ? ? ? $chunkno++;
? ? ? ? $size = 0;
? ? }
? ? $size += strlen(json_encode($set)) + 1;
? ? $chunk[] = $set;
? ? //? unset($data[$n]); // in case of memory issues, see notes
}
如果您對影響感到好奇。通過這種方法,內(nèi)存使用量達到(已用,最大)1.06 MB、29.34 MB。使用單獨的寫入例程,26.29 MB、31.8 MB。兩個數(shù)字都包括unset($data)調(diào)用、取消初始數(shù)組并釋放內(nèi)存。CPU 方面,兩個選項之間沒有顯著差異。
人們還可以$data在每次添加到 后清除數(shù)組的成員$chunk[],但是在 5MB 塊大小下,這里的內(nèi)存優(yōu)勢可以忽略不計。初始數(shù)組本身的加載/定義是昂貴的,是最大內(nèi)存使用量的主要因素。(在任何處理開始之前,我使用的測試數(shù)組占用了 29.25 MB。)

TA貢獻1895條經(jīng)驗 獲得超7個贊
您可以獲取strlen字節(jié)并從那里進行計算:
$total_size = strlen(json_encode($array)) / 1024 / 1024;
$chunk_size = floor($total_size / 5);
$chunked_array = array_chunk($array, $chunk_size);
foreach($chunked_array as $key => $chunk) {
$i = $key + 1;
file_put_contents("file{$i}.json", json_encode($chunk));
}
獲取 JSON 編碼數(shù)組的總大小(以字節(jié)為單位)并轉(zhuǎn)換為 MB
將總大小除以 5MB 即可得到塊大小
將數(shù)組分成塊大小
循環(huán)和 JSON 編碼每個塊并寫入文件
或者您可以進行計算:
$total_size = strlen(json_encode($array)); $chunk_size = floor($total_size / (5 * 1024 * 1024));

TA貢獻1801條經(jīng)驗 獲得超8個贊
讓我們假設(shè)每個項目都具有相同的結(jié)構(gòu):
1500 項 ~= 5MB
25500 items = ~85MB
85MB / 5MB = 17
25500 / 17 = 1500 items
代碼可以是這樣的:
foreach(array_chunk($array, 1500) as $arr){
// save array in some file
}

TA貢獻1829條經(jīng)驗 獲得超9個贊
請嘗試以下解決方法:
<?php
$array = array (
0 => array (
'category' => '179535',
'email' => NULL,
'level' => 1,
'name' => 'FOO'
),
1 => array (
'category' => '1795',
'email' => NULL,
'level' => 1,
'name' => 'BARFOO'
),
2 => array (
'category' => '16985',
'email' => NULL,
'level' => 1,
'name' => 'FOOBAR'
)
);
$len = sizeof($array);
$fileNameIndex = 1;
for($i=0;$i<$len;$i++)
{
$fileName = 'file'.$fileNameIndex.'.json';
$fileExist = file_exists($fileName);
$fileSize = 0;
$mode ='w';
$current = null;
if($fileExist)
{
$fileSize = fileSize($fileName);
$current = json_decode(file_get_contents($fileName), true);
}
if($fileExist && $fileSize < 5242880)
{
WriteToFile($fileNameIndex, $current, $array[$i], $i);
}
else if(!$fileExist)
{
WriteToFile($fileNameIndex, $current, $array[$i], $i);
}
else
{
$fileNameIndex ++;
WriteToFile($fileNameIndex, $current, $array[$i], $i);
}
}
function WriteToFile($fileNameIndex, $current, $data, $i)
{
$fileName = 'file'.$fileNameIndex.'.json';
$mode ='w';
echo "$i index array is being written in $fileName. <br/>";
$fileNameIndex ++;
$fp = fopen($fileName, $mode);
if($current)
{
array_push($current, $data);
}
else
{
$current = [];
array_push($current, $data);
}
fwrite($fp, json_encode($current));
fclose($fp);
}
?>
- 4 回答
- 0 關(guān)注
- 175 瀏覽
添加回答
舉報