如果你想用PHP处理大文件,PHP提供了一些普通的PHP函数,比如file_get_contents()或file()函数,它们在处理超大文件时会存在一定局限性。中福在线源码搭建QQ:2152876294 网址diguaym.com
其中包括:
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;
}
读取二进制文件
来看另一个读取二进制的文件:
function DisplayWindowSize(){
var w=window.innerWidth
|| document.documentElement.clientWidth
|| document.body.clientWidth;
}
直接读取
现在我们将定义一个采用迭代的类型,返回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文件中自动加载该类并直接使用。