php7:大数据文件提取 | 将电子表格上传到数据库中_fileiteratorbylength_su_yi_song的博客-程序员秘密

技术标签: php7  

谈到这两个功能的共通处就是都需要对大数据文件进行处理。

大数据文件处理

思想: php本身存在几个文件读取方法如file_get_content()和file()方法,的确这两个方法的处理速度速度快且容易使用,但由于php对内存的限制(php.ini memeory_limit=128M)而且一次性读取整个文件的可读性差(等待时间过长),因此需要一种大数据文件处理方法。php处理大数据文件的机制就是使用splfileObject类和yield生成器来定量一行行提取。

重点:
在上一次谈php读取文件IP地址就涉及到了对SplFileObject和yield生成器中的使用,这里只谈一下NoReWindIterator类。
php官网描述:This iterator ignores rewind operations. This allows processing an iterator in multiple partial foreach loops. (此迭代器忽略倒带操作。这允许在多个部分foreach循环中处理迭代器。 )
就我而言,这个类的作用就是一个得到的迭代器只能循环一次,后面多次循环不会得到任何结果

后面就直接给代码了:
大数据文件处理类:

<?php

/*
 * 遍历大数据文件:
 * 使用yield生成器输出,不使用file_get_content和file()函数,使用SplFileObject类处理
 * 三种遍历方式:逐行输出、定量输出、NoReWindIterator输出
 *
 * */
namespace Application\Iterator;

use Exception;
use InvalidArgumentException;
use SplFileObject;
use NoRewindIterator;

class LargeFile{
    
    const ERROR_UNABLE = "ERROR:UNABLE TO OPEN THE FILE!";
    const ERROR_TYPE = "ERROR:TYPE MUST BE 'ByLength','ByLine' or 'Csv'";

    protected $file;
    protected $allowTypes = ['ByLine','ByLength','Csv'];

    //构造器初始化参数
    function __construct($filename, $mode='r')
    {
    
        if(!file_exists($filename)){
    
            $message = __METHOD__.':'.self::ERROR_UNABLE.PHP_EOL;
            $message.= strip_tags($message);
            throw new Exception($message);
        }
        $this->file = new SplFileObject($filename, $mode);
    }

    //逐行遍历
    public function fileIteratorByLine(){
    
        $count = 0; //统计行数
        while(!$this->file->eof()){
    
            yield $this->file->fgets(); //读取一行内容
            $count++;
        }
        return $count;
    }

    //逐长度遍历,fread方法,protected类型方法,不能同时以两种方式遍历
    protected function fileIteratorByLength($numBytes = 1024){
    
        $count = 0;
        while(!$this->file->eof()){
    
            yield $this->file->fread($numBytes);
            $count++;
        }
        return $count;
    }

//NoRewindIterator对象只能遍历一次,而直接用生成器的话可以循环多次
    public function getIterator($type='ByLine', $numBytes=null){
    
        //判断类型是否满足条件
        if(!in_array($type,$this->allowTypes)){
    
            $message = __METHOD__.':'.self::ERROR_TYPE.'<br />';
            //$message.= strip_tags($message);
            throw new InvalidArgumentException($message);   //异常即中止
        }
        $iterator = 'fileIterator'.$type;
        return new NoRewindIterator($this->$iterator($numBytes));   //返回一个对象去执行相应的生成器方法,构造方法的参数是一个生成器
    }
}

测试代码

<?php
header("Content-type:text/html;charset=utf8");
require_once __DIR__.'/../AutoLoad/Loader.php';
\AutoLoad\Loader::init(__DIR__.'/../../');

use \Application\Iterator\LargeFile;

define('MASSIVE_FILE',__DIR__.'/War_And_Peace.txt');
try{
    
    $largeFile = new LargeFile(MASSIVE_FILE);
    //获得迭代器
    $iterator = $largeFile->getIterator('ByLine');

    $words = 0;
    foreach ($iterator as $line){
    
        echo $line."<br />";
        //preg_match_all("/([a-z]+)/i",$line,$match);
        //$words += count($match[0]);
        $words += str_word_count($line);    //统计字符串中的单词数,不包括汉字
    }
    echo str_repeat('-',52)."<br />"; //重复一个字符串multiplier次
    printf("%-40s : %8d\n",'Total Words:',$words);
    printf("%-40s : %8d\n",'Average words per line:',($words/ $iterator->getReturn())); //getReturn返回生成器的返回值
    echo str_repeat('-',52)."<br />";

}catch (Throwable $e){
      //Throwable式throw抛出的错误或异常对象的基本接口
    echo $e->getMessage();  //执行类方法时抛出的异常
}

涉及通用方法:

  • strip_tags():去除html和php标记
  • str_word_count():统计单词个数,不包含汉字

结果:统计<战争与和平>
在这里插入图片描述
在这里插入图片描述文本的方式是实时输出的。

将电子表格上传到数据库中

这里显示的将个人信息csv文件上传到数据库中。
思想: 首先说明一下php只提供了处理csv文件(逗号分隔型取值格式),因此在处理excel等电子文件需要先转化为csv文件。

重点

  • SplFileObject的fgetcsv()方法取一行数据并返回一个数组
  • php中PDO处理数据库
  • 遍历大数据的csv文件

之所以将这两个功能放一块,因为两者都需要LargeFile类来处理文件。

介绍一下PDO处理步骤:

  1. 得到一个PDO连接对象,参数如下字符串

  2. 预处理/执行(prepare/execute)机制执行sql语句,先执行prepare方法,再执行execute方法

创建数据库:
可使用navicat创建数据库,也可直接通过命令行创建
在这里插入图片描述
命令:

CREATE TABLE `NewTable` (
`id`  int(4) UNSIGNED NOT NULL AUTO_INCREMENT ,
`name`  varchar(20) NOT NULL COMMENT '姓名' ,
`sex`  char(3) NOT NULL COMMENT '性别' ,
`age`  int(2) UNSIGNED NOT NULL ,
`height`  double(4,2) UNSIGNED NOT NULL ,
`email`  varchar(30) NULL ,
`telephone`  varchar(20) NOT NULL ,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
COMMENT='个人信息'
;

代码:
数据库处理类:

<?php

namespace Application\Database;

use Exception;
use PDO;        //数据库连接处理对象

class Connection{
    
    const ERROR_UNABLE = "ERROR:Unable to create database connection!";
    public $pdo;    //pdo数据库连接对象

    //构造方法连接数据库
    function __construct($config)
    {
    
        //mysql或其它数据库
        if(!isset($config['driver'])){
    
            $message = __METHOD__.":".self::ERROR_UNABLE."<br />";
            throw new Exception($message);
        }
        //处理连接字符串
        $dsn = $config['driver'].":host=".$config['host'].";dbname=".$config['dbname'];

        try{
    
            //生成PDO对象,PDO的参数
            $this->pdo = new PDO($dsn, $config['user'], $config['password'],[PDO::ATTR_ERRMODE=>$config['errmode']]);
            
        }catch (\PDOException $e){
      //PDO异常
            error_log($e->getMessage());    //抛出异常
        }
    }
}

读取文件类:
在上面largeFile.php中添加遍历csv文件方式:

//Csv遍历,遍历电子表格
protected function fileIteratorCsv(){
    
    $count = 0;
    while(!$this->file->eof()){
    
        yield $this->file->fgetcsv();   //返回一行数据
        $count++;
    }
    return $count;
}

配置文件:

<?php

return [
    'driver'=>'mysql',
    'host'=>'localhost',
    'dbname'=>'newphp',
    'user'=>'root',
    'password'=>'forlove123',
    'errmode'=>PDO::ERRMODE_EXCEPTION
];

测试代码:

<?php
header("Content-type:text/html;charset=utf8");
/*
 * 加载电子表格csv到数据库中
 * */

define('DB_CONFIG_FILE',__DIR__.'/../data/config/db.config.php');
define('CSV_FILE',__DIR__.'/../data/files/PersonalInfo.csv');
require_once __DIR__.'/../AutoLoad/Loader.php';

\AutoLoad\Loader::init(__DIR__.'/../../');  //初始目录

use Application\Database\Connection;
use Application\Iterator\LargeFile;

try{
    
    $connection = new Connection(include DB_CONFIG_FILE);   //include直接返回配置数组
    $iterator = (new LargeFile(CSV_FILE))->getIterator('Csv');

    //PDO的预处理/执行(prepare/execute执行功能)
    $sql = "insert into `PersonalInfo` (`id`, `name`, `sex`, `age`, `height`, `email`, `telephone`) values (?,?,?,?,?,?,?)";
    $statement = $connection->pdo->prepare($sql);   //预处理
    echo '<pre>';
    print_r($statement);
    echo '</pre>';

    //执行插入
    foreach ($iterator as $line) {
    
        array_unshift($line, null);
        var_dump($line);
        echo '<br />';
        //执行
        $statement->execute($line);
    }

}catch (Throwable $e){
    
    echo $e->getMessage();
}

echo '1';   //catch会捕获异常但程序仍然会继续执行


结果
Personal.cs文件:
在这里插入图片描述
数据库:
在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/su_yi_song/article/details/107619579

智能推荐

ClassNotFoundException:org.hibernate.hql.ast.HqlToken_w0w13g6g872q1q的博客-程序员秘密

错误:用weblogic部署项目,访问时报错ClassNotFoundException:org.hibernate.hql.ast.HqlToken 解决方法: 1、命令窗口下启动weblogic: http://guojuanjun.blog.51cto.com/277646/288121 a:拷贝Hibernate3里带的包antlr-2.7.5H3.jar到%WL_HOME%\server...

vue.js创建引入组件_用Vue.js创建的简单聊天组件_cuk5239的博客-程序员秘密

vue.js创建引入组件 快速聊天 (vue-quick-chat)This vue component is a simple chat that can be easily imported and used in your project. 该vue组件是一个简单的聊天程序,可以轻松导入并在项目中使用。 特征 (Features)Custom style 定制风格 Handle ...

基于libjpeg实现的jpeg解码demo_背姑娘的锅的博客-程序员秘密

使用的libjpeg版本为jpegsr9b,在上一篇blog有libjpeg在VS2012下的编译步骤: VS2012编译libjpeglibjpeg解码jpeg图片解码调用流程如下:static bool _jpgToRGBColor(PICTUREINFO picInputInfo, PICTUREINFO *picOutputInfo){ struct jpeg_de

Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException:_清~净的博客-程序员秘密

Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException:

手把手教你构建 Kubernetes 1.8 + Flannel 网络(一)_weixin_34396103的博客-程序员秘密

环境说明操作系统:CentOS7Kubernetes版本:v1.8.4Docker版本:v17.06-ceFlannel 版本: flannel-v0.9.1Ntp 服务器配置时间同步很重要[[email protected] ~]# yum install ntp-server -y[root@node1 ~]# systemctl start ntpd &amp;&amp; systemctl ...

随便推点

IDEA给class类添加main入口方法_设置一个主函数入口main class_美奇开发工作室的博客-程序员秘密

导读:在java开发中,我们在做代码测试时经常需要用到main入口方法,在使用Eclipse开发工具的时候,我们直接录入main并使用alt+/方法,即可快速录入main方法;但是在IDEA中我们直接使用该组合键却没有效果,原因在于没有添加方法Template模板,以下介绍如何自定义设置添加方法模板。1、打开IntelliJ IDEA → File → Settings... → 点开Editor选项2、选择该选项下的Live Templates,点击右侧加号添加一个组,选择T...

Unreal Engine 4 —— GAS系统学习 (二十) 为主角添加冲刺技能眩晕_虎牙维护世界和平的博客-程序员秘密

欢迎大家加入Unreal Engine C++ &amp; Blueprint群一起交流:1143575617这里的释放技能后的眩晕其实要打个引号,只是主角暂时不可控制,并不是真正的眩晕技能或者播放一段眩晕的动画。打开主角C++文件,在头文件上加入以下代码:public: UFUNCTION(BlueprintCallable, Category = "Shinbi | Stun") void hitStun(float Duration);protected: UFUNCTIO.

python 安装graphviz_python怎么安装graphviz_qq_33445377的博客-程序员秘密

Anaconda是一个用于科学计算的Python发行版,支持 Linux, Mac, Windows系统,提供了包管理与环境管理的功能,可以很方便地解决多版本python并存、切换以及各种第三方包安装问题。Anaconda利用工具/命令conda来进行package和environment的管理,并且已经包含了Python和相关的配套工具。

linux内核剪裁_weixin_30716725的博客-程序员秘密

首 页 阅览室 馆友 我的图书馆 登录注册 Linux内核裁剪与移植linux内核裁剪的具体过程和方法 这是我前段时间自己整的一份,内核功能: 能够完成系统的基本功能,上网,收发邮件等,支持xwindows图形界面。 在menuconfig中配置: 详细介绍内核配置选项及删改情况 第一部分:全部删除 Code maturity level options ---...

oracle dbms ijob,DBMS_IJOB包实践_Hey'u的博客-程序员秘密

背景:工作中需要使用新的scheme去上传、更新另一个scheme下的对象,话说这么做本身就不太合适但是出于安全等各种原因吧事实就是这样了,DMLDDL都可以通过赋权限做到,遇到的一个难题是:如果管理另一个scheme下的job?据我之前的了解,oracle的job只是当前scheme可以管理,sys都不能管理另外一个scheme下的job;现在发现,这个认识是需要更正的,正确的说法是,通过dbm...