简略的文件读取,个别咱们会应用 file_get_contents() 这类形式来间接获取文件的内容。不过这种函数有个重大的问题是它会把文件一次性地加载到内存中,也就是说,它会受到内存的限度。因而,加载大文件的时候是相对不能应用这种形式的。咱们还是先看看这种形式加载的例子。
// 一般的文件读取 一个 2.4G 的 SQL 导出文件
$fileName= './2020-02-23.sql';
// file_get_contents
$fileInfo = file_get_contents($fileName);
// Fatal error: Allowed memory size of 134217728 bytes exhausted
// file
$fileInfo = file($fileName);
// Fatal error: Allowed memory size of 134217728 bytes exhausted
// fopen + fread
$fileHandle = fopen($fileName, 'r');
$fileInfo = fread($fileHandle, filesize($fileName));
// Fatal error: Allowed memory size of 134217728 bytes exhausted
上述三种模式的文件加载读取形式都是不能加载这么大的文件的,当然,你也能够批改 php.ini 中的相干配置让他们可能加载胜利,但咱们并不举荐这样应用,毕竟内存资源相比硬盘资源还是要贵重的多。
以下的形式是能够间接读取这种大文件的:
// readfile 只能间接输入
echo readfile($fileName);
// fopen + fgetc 如果单
$fileHandle = fopen($fileName, 'r');
// 输入单字符直到 end-of-file
while(!feof($fileHandle)) {echo fgetc($fileHandle);
}
fclose($fileHandle);
// SplFileObject
$fileObject = new SplFileObject($fileName, 'r');
while(!$fileObject->eof()){echo $fileObject->fgetc();
}
第一个 readfile(),读取文件后就间接打印了,不能进行其余操作,实用于间接显示大文件内容时应用。
第二个 fopen() 配合 fgetc() 或 fgets() 是读取这种大文件的标配。fopen() 获取文件句柄,fgetc() 按字符读取,fgets() 按行读取。像这个 mysqldump 进去的文件,一行也可能十分的大,所以咱们就只能间接按字符读取。
第三个是 SPL 扩大库为咱们提供的面向对象式的 fopen() 操作,倡议新的开发中如果有读取大文件的需要最好应用这种模式的写法,毕竟 SPL 函数库曾经是 PHP 的规范函数库了,而且面向对象的操作模式也更加的支流。
下面三种读取形式都有一个要留神的点是,咱们将大文件读取后不应该再保留到变量中,应该间接打印显示、入库或者写到其余文件中。因为间接读取到一个变量中就和后面的间接读取到内存的形式一样了,那还不如间接去批改下 php.ini 的配置而后应用最上方的形式间接读取到内存不便。还是那句话,内存留给真正须要它的中央,这种大文件,最好还是进行硬盘的 IO 操作。
测试代码:
https://github.com/zhangyue0503/dev-blog/blob/master/php/202003/source/PHP%E5%A4%A7%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96%E6%93%8D%E4%BD%9C.php
参考文档:
《PHP7 编程实战》
各自媒体平台均可搜寻【硬核项目经理】