在 PHP 中,有多种简单的方式实现文件读取:file(),file_get_contents(),readfile()……
不同的实现方法,对内存的消耗不同。例如,file() 将整个文件内容读入一个数组,file_get_contents() 将整个文件读入一个字符串,此时内存的消耗取决于文件的大小。
通过对以下三种读取文件方式在内存消耗方面的比较,以后在遇到类似的问题时,可以更合理的选择处理方式。
⒈ 传统的按行读取文件
// common.php
/**
* 公共方法,用于文件单位之间的转换
*
* @param int $bytes 以字节计的文件大小
* @param int $precision 精度(经单位转换后保留的小数位数)
*/
function getReadableSize(int $bytes, int $precision = 2)
{
$units = ['b', 'k', 'm', 'g', 't'];
$bytes = max($bytes, 0);
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
$pow = min($pow, count($units) - 1);
$bytes /= (1 << 10 * $pow);
return round($bytes, $precision) . ' ' . $units[$pow];
}
require 'common.php';
$file = $path . '/shakespeare.txt';
if (!file_exists($file)) {
return false;
}
$fp = fopen($file, 'r');
$lines = [];
while(!feof($fp)) {
$lines[] = fgets($fp);
}
fclose($fp);
return $lines;
echo '文件大小:' . getReadableSize(filesize($file)) . PHP_EOL;
echo '内存使用:' . getReadableSize(memory_get_peak_usage()) . PHP_EOL;
经测试,使用这种方式读取文件,文件本身大小为 5.2M,最大内存消耗量为 13M。
⒉ 使用生成器读取文件内容
require 'common.php';
function readFileWithYield(string $file)
{
$fp = fopen($file, 'r');
while(!feof($fp)) {
yield fgets($fp);
}
fclose($fp);
}
$file = $path . '/shakespeare.txt';
if (!file_exists($file)) {
return false;
}
$str = '';
$i = 0;
foreach(readFileWithYield($file) as $line) {
preg_match("/\n{3}/", $str, $matches);
if (count($matches)) {
$i ++;
$str = '';
} else {
$str .= $line . PHP_EOL;
}
}
echo $i . PHP_EOL;
echo '文件大小:' . getReadableSize(filesize($file)) . PHP_EOL;
echo '内存使用:' . getReadableSize(memory_get_peak_usage()) . PHP_EOL;
经测试,使用这种方式读取文件,文件本身大小为 5.2M,最大内存消耗量为 433K。
⒊ 使用流传输的方式读取文件
require 'common.php';
$file = $path . '/shakespeare.txt';
if (!file_exists($file)) {
return false;
}
$fp = fopen($file, 'r');
$fp_copy = fopen('./copy.txt', 'w');
stream_copy_to_stream($fp, $fp_copy);
fclose($fp);
fclose($fp_copy);
echo '文件大小:' . getReadableSize(filesize($file)) . PHP_EOL;
echo '内存使用:' . getReadableSize(memory_get_peak_usage()) . PHP_EOL;
经测试,使用这种方式读取文件,文件本身大小为 5.2M,最大内存消耗量为 430K。