PHP读取大文件

简介: PHP读取大文件

@[toc]

单线程读入

如果不考虑多线程的情况下,单线程读取大文件采用while fread就可以实现。

$handle = fopen("./big.txt", "rb");
while (!feof($handle)) {
   
  {
   mathJaxContainer[0]}handle, 8192);
  // 业务处理
  unset($contents); // 释放掉变量
}
fclose($handle);

feof是判断是否到文件尾,如果没有到文件尾,则会一直while循环,并执行读取操作。每次读取8192字节,然后使用过后将其释放掉。
往往很多文件并不是一行的,有多行内容。需要将每行内容读取出来当做一条数据处理,也可以使用fgets。

$handle = fopen("./big.txt", "rb");
while (!feof($handle)) {
   
  {
   mathJaxContainer[1]}handle, 1024);
  // 业务处理
  unset($contents); // 释放掉变量
}
fclose($handle);

这里的fgets第二个参数,默认为1024字节。即默认读取一行数据,如果一行数据小于1024字节,则完整读取。如果超出1024字节,则只取前1024字节。遇到换行符"\n"或者"\r\n"或者结束符会停止读取。
如果遇到变态的文件,很多行都只有1000长度,某一行有8000长度,如果在不清楚的情况下,就很难掌控,若要完整读取就需要指定读取的最大字节,8000才能将每一行完整读取。
还有一种方法就是自己处理换行符。默认读取1024字节,然后放置到内存中,使用过后再将其释放。这种操作很节省内存,但是在逻辑处理上需要自己处理换行符。
如,读取1024字节,没有换行符,则保存数据继续读取。再读取1024字节,判断其中是否有换行符,如果有则处理最开始到换行符中的数据。再将剩下的数据保存,等待下一次读取,直到整个文件读取完毕。

$handle = fopen("./big.txt", "rb");
$contents = "";
while (!feof($handle)) {
   
  {
   mathJaxContainer[2]}handle, 8192);

  // 判断读取到的内容是否包含换行符,包含则进入循环体
  while(strpos($contents, "\n") !== false){
   
      {
   mathJaxContainer[3]}contents, "\n");
      {
   mathJaxContainer[4]}contents, 0, $eol_pos);
      // $line为一行的数据,进行业务处理,并释放
      unset($line);

      {
   mathJaxContainer[5]}eol_pos, 0);// 将剩余内容放置到变量中以供下次使用
  }
}
fclose($handle);

多线程读取

PHP默认没有多线程,这里可以采用多进程的方式实现,或者swoole的多进程来实现。
例如读取一个8GB文件,分8个线程,每个线程读取1GB数据内容。或者更多线程进行拆分工作内容。

获取文件大小

首先第一步,就是获取整个文件的体积大小,然后计算每个线程应该负责处理的一部分内容。

function length($filename)
{
   
    {
   mathJaxContainer[6]}filename, "rb");
    {
   mathJaxContainer[7]}handle);
    fseek($handle, 0, SEEK_END);
    {
   mathJaxContainer[8]}handle);
    fseek({
   mathJaxContainer[9]}currentPos);
    // $length 文件总长度
    return $length;
}
echo length("./big.txt");

处理逻辑实现过程

这里主要说明下作了哪些内容,首先是设定分配总的线程数。然后根据设置的线程数,计算每个线程要读取的数据大小,即从哪里开始读,读到哪里结束。
然后必定会出现拆分后,读到不完整行的情况,在这里来解决这种前半行或者后半行的意外情况。
解决逻辑就是,假设线程开始的读取位置在某一行的中间,我们一个字符向前移动,移动到上个换行符(也可能是最开始)即可获取到整行文本内容。
处理掉残行数据之后,使用yield来传递数据给业务处理。

$filename = "./big.txt";
$maxProcess = 8;// 分配8个线程


{
   mathJaxContainer[10]}filename);
{
   mathJaxContainer[11]}length / $maxProcess);

// 线程负责读取的内容
function processRead({
   mathJaxContainer[12]}index, $singleProcessLength)
{
   
    {
   mathJaxContainer[13]}filename, 'r');

    {
   mathJaxContainer[14]}index * $singleProcessLength;
    //结束位置=线程序列*线程处理数据长度+线程处理数据 - 1 (长度转指针,实际结束指针小于结束长度)
    {
   mathJaxContainer[15]}index * {
   mathJaxContainer[16]}singleProcessLength - 1;

    fseek({
   mathJaxContainer[17]}beginPos);
    echo '线程:' . {
   mathJaxContainer[18]}beginPos . ',结束位置:' . $endPos . PHP_EOL;
    //移动到上个\n 以便首次顺利获取整行内容
    while (fseek($fh, -1, SEEK_CUR) === 0) {
   
        if (fread({
   mathJaxContainer[19]}fh) <= 0) {
   
            break;
        }
        fseek($fh, -1, SEEK_CUR);
    }
    echo '线程:' . $index . ',移动完毕!!!!!' . PHP_EOL;

    //整行读取数据
    //结束时位置超过预计结束位置是正常状况,fgets 读取一整行内容
    //预计结束位置可能在行内,所以产生不同结果。
    while (ftell({
   mathJaxContainer[20]}endPos && !feof($fh)) {
   
        yield {
   mathJaxContainer[21]}fh);
    }
    echo '进程' . {
   mathJaxContainer[22]}fh) . ', 应该到:' . $endPos . PHP_EOL;
    fclose($fh);
}

foreach(range(0,{
   mathJaxContainer[23]}index){
   
    // 多线程采用多线程的方式创建,这里采用yield回调。
    foreach(processRead({
   mathJaxContainer[24]}index, {
   mathJaxContainer[25]}value){
   
        // $value为每一行的内容,处理后释放
        unset($value);
    } 
}

如上所述就是PHP的大文件读取解决方案,大部分用于多线程读取大文件场景。

目录
相关文章
|
7月前
thinkphp5.1隐藏index.php入口文件
thinkphp5.1隐藏index.php入口文件
62 0
thinkphp5.1隐藏index.php入口文件
|
3月前
|
PHP
php常见问题,php.ini文件不存在或者找不到,mb_strlen()函数未定义系列问题,dll模块找不到的解决
本文介绍了解决PHP常见问题的步骤,包括定位和创建`php.ini`文件,以及解决`mb_strlen()`函数未定义和DLL模块加载错误的具体方法。
php常见问题,php.ini文件不存在或者找不到,mb_strlen()函数未定义系列问题,dll模块找不到的解决
|
6月前
|
存储 运维 Serverless
函数计算产品使用问题之在YAML文件中配置了环境变量,但在PHP代码中无法读取到这些环境变量,是什么原因
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
3月前
|
前端开发 PHP
php学习笔记-php文件表单上传-day06
本文介绍了PHP文件上传处理流程、预定义变量`$_FILES`的使用、文件上传状态代码以及文件上传实现函数。同时,通过一个文件上传的小例子,演示了文件上传表单的创建、文件上传表单处理的PHP页面编写以及运行测试输出。
php学习笔记-php文件表单上传-day06
|
3月前
|
缓存 监控 算法
分析慢日志文件来优化 PHP 脚本的性能
分析慢日志文件来优化 PHP 脚本的性能
|
3月前
进入靶场,出现一张照片,右击查看源代码,发现有一个注释的source.php文件
这段代码实现了一个网站上弹出的促销海报动画效果,包含一个关闭按钮。当促销海报弹出时,会在三秒后开始抖动一两下。海报使用固定定位居中显示,带有阴影和圆角,关闭按钮位于右上角。可以通过修改时间参数调整弹出时间。
20 0
|
4月前
|
存储 安全 数据库连接
php.ini 文件的用途是什么?
【8月更文挑战第29天】
75 1
|
4月前
|
PHP
PHP遍历文件并同步上传到服务器
在进行网站迁移时,由于原网站的图片文件过多,采用打包下载再上传的方式耗时过长,且尝试使用FTP工具从旧服务器传输至新服务器时失败。为解决此问题,特使用PHP编写了一款工具,该工具能扫描指定目录下的所有`.webp`图像文件,并将其上传至新的服务器,极大地提高了迁移效率。
106 16
|
4月前
|
Java 应用服务中间件 PHP
PHP——调用java文件中的方法
PHP——调用java文件中的方法
59 0
PHP——调用java文件中的方法