Наиболее эффективный с точки зрения памяти способ разделения блоков переменного размера?
Есть ли способ сделать что-то вроде fread
, но с переменной?
То есть я хочу "читать" другую переменную в памяти по 1 МБ за раз.
Таким образом, у меня могло бы быть что-то вроде этого:
$data = ... ; // 10MB of data
$handle = fopen($data, "rb"); // Need something instead of fopen here
while (!feof($handle))
{
$chunk = fread($handle, 1048576); // Want to read 1MB at a time
doSomethingWithChunk($chunk);
}
fclose($handle);
У меня есть большой двоичный файл, загруженный в память, около 10 МБ. Я бы хотел разделить его на массив из блоков размером 1 МБ. Мне не нужны все куски размером 1 МБ в памяти сразу, поэтому я думаю, что мог бы сделать что-то подобное выше более эффективно, чем просто использовать встроенный PHP str_split функция.
2 answers
Невозможно последовательно "прочитать" строку, которая уже загружена в память; на самом деле не более эффективно разделять ее. Накладные расходы нескольких переменных также потребляют больше памяти, чем одна. В идеале вы бы загрузили строку в поток, но в PHP на самом деле нет потока строк.
Если вы просто хотите работать со строкой по частям, вы можете просто перебирать ее подстроки:
$data;
$pointer = 0, $size = strlen($data);
$chunkSize = 1048576;
while ($pointer < $size)
{
$chunk = substr($data, $pointer, $chunkSize);
doSomethingWithChunk($chunk);
$pointer += $chunkSize;
}
Я не уверен, как PHP обрабатывает большие строки внутренне, но в соответствии со строковой документацией , строка может быть только "размером до 2 ГБ (максимум 2147483647 байт)". Если ваш файл размером около 10 МБ, это не должно быть проблемой для PHP.
Другой вариант (возможно, лучший вариант) - загрузить $data
в память или временный поток . Если вы хотите избавить среду от избыточной памяти, вы можете использовать оболочку потока php://temp
, где некоторые данные хранятся во временном файле, если он превышает 2 МБ. Просто загрузите строку в поток как можно скорее, чтобы сэкономить память, а затем вы можете использовать функции файлового потока для нее.
$dataStream = fopen("php://temp", "w+b");
fwrite($dataStream, funcThatGetsData()); // try not to put data into a variable to save memory
while (!feof($dataStream))
{
$chunk = fread($dataStream, 1048576); // want to read 1MB at a time
doSomethingWithChunk($chunk);
}
fclose($dataStream);
Если вы получаете $data
из другой функции, вы можете вместо этого передать $dataStream
. Если вам необходимо заранее ввести $data
в строку, обязательно вызовите unset()
, чтобы освободить память:
$data = getData(); // string from some other function
$dataStream = fopen("php://temp", "w+b");
fwrite($dataStream, $data);
unset($data); // free 10MB of memory!
...
Если вы хотите сохранить все это в памяти, вы можете использовать php://memory
, но в этом случае вы можете просто использовать строку.
Вы можете использовать как;
$handle = @fopen("path_to_your_file", "r");
if ($handle) {
while (($buffer = fgets($handle, 1024)) !== false) {
doSomethingWithChunk($buffer );
}
fclose($handle);
}