如果你想用PHP处理大文件,PHP提供了一些普通的PHP函数,比如file_get_contents()或file()函数,它们在处理超大文件时会存在一定局限性。 其中包括: 1.内存限制 上面这些函数依赖于php.ini中memory_limit的参数值设置,可以调整增加这些值,但这些函数仍然不适合极大的文件,因为这些函数会把整个文件内容都读入到内存中。 如果文件的尺寸超过memory_limit的设置,这类文件都不会加载到内存中。现实中,比如我们有一个20G的的文件,想用PHP来处理,该怎么样处理? 2.不太好的用户体验 还有一个限制是生产环境的速度问题。如果我们把它输出到数组中,这样经常会出现在浏览器出现很长时间的等待,白页或者出错等情况。这样给用户的体验不太好。 对于这种技术限制,可以使用yield关键字来直接生成一个结果。 SplFileObject Class 在本文中,我们告诉大家使用PHP标准库中的SplFileObject类。 我们来演示,创建一个类来处理大文件。 这个类使用文件名做为输入参数。如下代码: class BigFile { protected $file;
public function __construct($filename, $mode = 'r') { if (!file_exists($filename)) {
throw new Exception('File not found'); }
$this->file = new SplFileObject($filename, $mode); }
} 接下来,我们定义一个遍历文件的方法,这个方法将使用fgets()函数一次读取文件一行。 我们也可以使用fread()函数的方法。 读取文本文件 fgets()适用于解析包含换行符的文本文件,而fread()适用于解析二进制文件。 该函数用于遍历文本文件的每一行内容。 protected function iterateText() { $count = 0;
while (!$this->file->eof()) {
yield $this->file->fgets();
$count++; } return $count; } 读取二进制文件 来看另一个读取二进制的文件: protected function iterateBinary($bytes) { $count = 0;
while (!$this->file->eof()) {
yield $this->file->fread($bytes);
$count++; } } 直接读取 现在我们将定义一个采用迭代的类型,返回NoRewindIterator实例的方法。 我们使用NoRewindIterator强制单向读取。 public function iterate($type = 'Text', $bytes = NULL) { if ($type == 'Text') {
return new NoRewindIterator($this->iterateText());
} else {
return new NoRewindIterator($this->iterateBinary($bytes)); }
} 整个类源文件如下如示: class BigFile { protected $file;
public function __construct($filename, $mode = 'r') { if (!file_exists($filename)) {
throw new Exception('File not found');
}
$this->file = new SplFileObject($filename, $mode); }
protected function iterateText() { $count = 0;
while (!$this->file->eof()) {
yield $this->file->fgets();
$count++; } return $count; }
protected function iterateBinary($bytes) { $count = 0;
while (!$this->file->eof()) {
yield $this->file->fread($bytes);
$count++; } }
public function iterate($type = 'Text', $bytes = NULL) { if ($type == 'Text') {
return new NoRewindIterator($this->iterateText());
} else {
return new NoRewindIterator($this->iterateBinary($bytes)); }
} } 解析大文件: 我们对类文件做如下测试: $largefile = new BigFile('file.csv');
$iterator = $largefile->iterate('Text'); // Text or Binary based on your file type
foreach ($iterator as $line) {
echo $line;
} 现在这个类可以读取任何尺寸的大文件,没有任何限制,无限大。 我们可以在Laravel项目中,将该类添加到composer.json文件中自动加载该类并直接使用。 从此,我们可以轻松使用PHP解析和处理大尺寸文件了。 Happy PHP Coding! 作者:飞花逐月 |
|