资讯专栏INFORMATION COLUMN

老旧话题:PHP读取超大文件

goji / 2389人阅读

摘要:然而,刚进来就拧螺丝的人如果能够对读取一个的超大文件有所见解的话,造火箭也是迟早的事儿。其中,用于告知当前文件读取指针所在位置,可以手动设定文件读取指针的位置。

作为一名常年深耕curd的PHPer,关注内存那是不可能的,反正apache或者fpm都帮我们做了,况且运行一次就销毁,根本就不存在什么内存问题。

然而偏偏就有些个不开眼的人把这些个东西当面试题,比如总有刁民用“php读取一个10G的超大文件”当面试题来问你。当然了,作为一个和我一样的普普通通的蠢货,你听到这个问题的第一瞬间是懵逼,第二瞬间是卧槽,第三瞬间是保持结巴状态。

“面试造火箭,入职拧螺丝”。然而,刚进来就拧螺丝的人如果能够对“PHP读取一个10G的超大文件”有所见解的话,“造火箭”也是迟早的事儿。当前为了能够来这里“拧螺丝”,还是得先搞定“读取10G文件”这个问题。

要想读取10G的文件,首先,你得有个10G的文件

... ...

其实,相对来说也是比较简单的事情,我们随便找一个nginx的日志文件,哪怕只有10KB,假设文件名是test.log,然后呢执行" cat test.log >> test.log ",听我说少年,30秒左右你就该按下ctrl + C了,比如我这里,你们感受一下:

202MB,作为实验演示,够意思了。难不成真要造10G的文件?

首先,我们尝试用php的file函数来作一把死,你们感受一下:


保存为test.php,然后命令行下执行一把,结果如下图所示:

这句英文的大概意思就是“PHP最大只给每个进程分配了128MB内存,然而你特么张口要202MB?”所以,我们修改一下php配置文件... ...

千万不要手软,把这个参数改成1024MB,然后再次执行上面的php脚本:

然后,我们再试试最爱的file_get_contents()函数,结果如下图:

文件已经一次性全部被载入到内存中并将文件的每一行保存到了一个php数组中,我的机器是10G内存+256G固态硬盘,一次性载入这个202MB的文件file函数用了0.67秒钟、file_get_contents函数用了0.25秒钟(看起来file_get_content要比file靠谱的多),不过,敲重点的我们调整了配置文件才可以读取202MB的文件,如果摆在我们面前的是一个100G的文件呢?或者说,系统提供的php配置最多之给20MB内存而你又无法修改呢?

我们重点是如何在内存有限的机器上读取体积几百倍于内存的文件。下面,我们把memory_limit调整成16M,开启困难模式。

202MB的文件,允许被分配的内存为16MB,所以,总体思路其实也很简单,就是一点儿一点儿地读,只要每次读取的内容小于16MB,那就一定不会有问题,首先我们感受一下一个字符一个字符读,出场嘉宾是fgetc函数:


运行结果如下图:

虽然只有给了16M内存,但我们还是成功将202M文件全部读出来了,只不过这个运行速度是差了那么点儿意思,不大行。不能一个字母一个字母地读,这次我们一行一行地读:


运行结果如下图:

一行一行果然比一个一个字符要快很多,转念一想吧,系统分配给我们的内存上限是16MB,那我们索性一次读取一定量容量数据看看,会不会更快:


保存代码,运行一把,屌了屌了!!!在内存有限的情况下,我们还把时间缩短到了0.1秒!

然后我们考虑将问题升级一下,依然是上述这个202M的文件,这次我们要求读取倒数后5行的内容,这个问题看起来屌了些许,用原来的fread啥的虽然奏效但总感觉比较愚蠢。所以,现在又得引入全新的函数来解决这个问题:ftell和fseek。其中,ftell用于告知当前文件读取指针所在位置,fseek可以手动设定文件读取指针的位置。我建议大家去手册上重点观摩一下fseek函数:点击这里。

 0 ){
  while( $ch != "
" ){
    fseek( $fp, $pos, SEEK_END );
    $ch = fgetc( $fp );
    $pos--;
  }
  $ch = "";
  $content .= fgets( $fp );
  $line--;
}
echo $content;
exit;

其中test1.log文件的内容如下:

aa
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
cccccccccccccccccccccccccccccccc
ffffdffffdffffdffffdffffdffffdffffdffffdffffdffffddd
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
ffffffffffffffffffffffffffffffff
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
cccccccccccccccccccccccccccccccc
ffffdffffdffffdffffdffffdffffdffffdffffdffffdffffddd
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
ffffffffffffffffffffffffffffffff
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
cccccccccccccccccccccccccccccccc
ffffdffffdffffdffffdffffdffffdffffdffffdffffdffffddd
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
ffffffffffffffffffffffffffffffff
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
cccccccccccccccccccccccccccccccc
ffffdffffdffffdffffdffffdffffdffffdffffdffffdffffddd
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
ffffffffffffffffffffffffffffffff
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
cccccccccccccccccccccccccccccccc
ffffdffffdffffdffffdffffdffffdffffdffffdffffdffffddd
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
ffffffffffffffffffffffffffffffff
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
cccccccccccccccccccccccccccccccc
ffffdffffdffffdffffdffffdffffdffffdffffdffffdffffddd
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
ffffffffffffffffffffffffffffffff
1111111111
2222222222

保存文件并运行,结果如下图所示:

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/29736.html

相关文章

  • 老旧话题:重新看看当年感觉很难的session

    摘要:在中,会为每个不同的用户生成一个随机的,每个人拥有的都是不同的。值得注意的是,过期了不代表这个文件会马上被垃圾回收机制删除掉,还是有可能会残存一段时间的。 原文地址:https://t.ti-node.com/thread/... 这基本上算是个老旧的话题了,几乎所有phper在第一次面试的时候都会被问到关于session的问题,如果不出意外,往往是如下三板斧: php的sessi...

    beanlam 评论0 收藏0
  • 老旧话题:重新看看当年感觉很难的session

    摘要:在中,会为每个不同的用户生成一个随机的,每个人拥有的都是不同的。值得注意的是,过期了不代表这个文件会马上被垃圾回收机制删除掉,还是有可能会残存一段时间的。 原文地址:https://t.ti-node.com/thread/... 这基本上算是个老旧的话题了,几乎所有phper在第一次面试的时候都会被问到关于session的问题,如果不出意外,往往是如下三板斧: php的sessi...

    wuaiqiu 评论0 收藏0
  • PHP超低内存遍历目录文件读取超大文件

    摘要:这篇笔记主要解决这么几个问题如何使用超低内存快速遍历数以万计的目录文件如何使用超低内存快速读取几百甚至是级文件顺便解决哪天我忘了可以通过搜索引擎搜到我自己写的笔记来看看。 这不是一篇教程,这是一篇笔记,所以我不会很系统地论述原理和实现,只简单说明和举例。 前言 我写这篇笔记的原因是现在网络上关于 PHP 遍历目录文件和 PHP 读取文本文件的教程和示例代码都是极其低效的,低效就算了,有...

    banana_pi 评论0 收藏0
  • PHP读取超大的excel文件数据的方案

    摘要:场景和痛点说明今天因为一个老同学找我,说自己公司的物流业务都是现在用处理,按月因为数据量大,一个差不多有百万数据,文件有接近,打开和搜索就相当的慢联想到场景要导入数据,可能数据量很大,这里利用常用的一些方法比如会常有时间和内存限制问题下面我 场景和痛点 说明 今天因为一个老同学找我,说自己公司的物流业务都是现在用excel处理,按月因为数据量大,一个excel差不多有百万数据,文件有接...

    dkzwm 评论0 收藏0
  • 【译】通过JavaScript发送表单

    摘要:能异步地发送任意数据的技术称为,表示异步的和。若你使用,使用发送表单还会影响同源策略,并导致内容被发送到一个无法访问的中。但要手动发送二进制数据的话,还有很多额外工作要做。用来发送二进制是很直接的,使用方法就好了。 系列文章说明 原文 在[发送表单数据]()一文中,HTML表单可以声明式地发送一个HTTP请求。但表单也可以用JavaScript来准备一个HTTP请求。本文将探索如何...

    chinafgj 评论0 收藏0

发表评论

0条评论

goji

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<