CSV类 批量导入数据 [基础教程]

作者:代号黑鹰 发布于:2016-12-18 浏览:985次 收藏

前言:

        想写一个批量导入数据的功能,在网上找了半天没有一个符合我要求的东西。我的要求如下:

            1: 读取一个文件流,以二维数组输出

            2:读取服务器一个存在的 demo.csv文件,以二维数组输出

            3:读取多个文件存在的csv后缀文件,以二维数组输出

            4:读取一个上传的csv后缀文件,以二维数组输出

            5:读取多个上传的csv后缀文件,以二维数组输出

            6:以一个二维数组,写一个csv后缀文件到服务器指定目录

            7:以一个二维数组,写一个csv后缀文件并下载

        没有办法网上找不到这样要求的类之前写过这样的东东,没有写笔记。话了一个小时弄了一下

       时间冲忙,有不足的或bug请在二群找《代号黑鹰》---此类的实现原创,如有雷同请自己剁手

实现思路:

            csv格式文件每一个字符串以逗号隔开的如下图对比

            csv格式文件用excel打开:

            {D2I7%H7CV@T0042$[6U{59.png

            用记事本打开效果:

            X6J}P%4FU0]]@E0)Z%M0`@L.png

 使用说明:这个与框架无关放到相应的地方修改一下命名空间即可(别问我为什么不写成组件的形式)

<?php
/**
 * from:原创-如有雷同纯属偶然
 * Created by DaiLinLin dailinlin@7477.com.
 * class: CSV操作类
 * Date: 2016/12/16
 * Time: 21:02
 */

namespace Org\Util;


class CSV
{
    private $config = array(
        'startRow'              =>  0,      //开始读取数据的行数
        'startColumn'           =>  0,      //开始读取数据的列数
        'maxLine'               =>  500,    //允许读取数据的最大行数
        'keys'                  =>  array(), //返回以keys的下标数组
        'trim'                  =>  false,   //实现双引号保留素材
        'header'                =>  array()  //头部
    );

    private $error = ''; //错误信息
    private $php_low=false;//判断是否是5.3低版本


    /**
     * 构造方法,用于构造CSV操作实例
     * @param array $config
     */
    public function __construct($config = array()){
        /* 获取配置 */
        $this->config   =   array_merge($this->config, $config);
        if(version_compare(PHP_VERSION,'5.4.0','<')){
            $php_low = true;
        }
    }

    /**
     * 使用 $this->name 获取配置
     * @param  string $name 配置名称
     * @return multitype    配置值
     */
    public function __get($name) {
        return $this->config[$name];
    }

    public function __set($name,$value){
        if(isset($this->config[$name])) {
            $this->config[$name] = $value;
        }
    }

    public function __isset($name){
        return isset($this->config[$name]);
    }

    /**
     * 返回错误信息
     * @return string
     */
    public function getError(){
        return $this->error;
    }

    /**
     * 读取单文件文件csv内容
     * @param $file
     * @return array|bool
     */
    public function importCSVOne($file){
        return $this->importCSV(array($file));
    }

    /**
     * 读取上传文件csv内容
     * @param string $files
     * @return array|bool
     */
    public function importCSV($files=''){
        if('' === $files){
            $files  =   $_FILES;
        }

        if(empty($files)){
            $this->error = '没有上传的文件!';
            return false;
        }

        foreach($files as $item){
            $exp = explode('.',$item['name']);
            if($exp[1]!='csv'){
                $this->error = '文件格式错误!';
                return false;
            }
        }

        $count = array();
        foreach($files as $item){
            $handle = fopen($item['tmp_name'],"r");
            $count = array_merge($count,$this->readHandleCSV($handle));
        }

        return $count;

    }

    /**
     * 读取存在路径文件的csv内容
     * @param $path
     * @return array|bool
     */
    public function readCSV($path){
        if(!file_exists($path)){
            $this->error = '文件路径不存在';
            return false;
        }
        $handle = fopen($path,"r");
        return $this->readHandleCSV($handle);
    }

    /**
     * 读取文件句柄csv内容
     * @param $handle
     * @return array
     */
    public function readHandleCSV($handle) {
        $out = array ();
        $n = 0;
        while ($data =$this->_fgetcsv($handle, $this->maxLine)) {

            //开始读取的行数
            if($n<$this->startRow){
                $n ++;
                continue;
            }

            //存在返回key的以key数组长度为一行长度
            $num = empty($this->keys)?count($data):count($this->keys);
            for ($i = $this->startColumn; $i < $num; $i++) {

                //没有key设置的放回数字下标数组
                $key = empty($this->keys[$i])?$i:$this->keys[$i];
                $data[$i] = $this->trim?trim($data[$i],"'"):$data[$i];

                $fileType = mb_detect_encoding($data[$i] , array('GB2312','GBK','UTF-8')) ;
                if($fileType == 'EUC-CN'){
                    $out[$n][$key] = iconv('GBK', 'utf-8', $data[$i]);
                }else{
                    $out[$n][$key] = $data[$i];
                }
            }
            $n++;
        }

        //关闭文件句柄
        @fclose($handle);
        return $out;
    }


    /**
     *  写csv文件
     * @param $path
     * @param $savename
     * @param $data
     */
    public function writeCSV($path,$savename,$data){

        if(!file_exists($path)){
            mkdir($path);
        }

        $file = fopen($path.'/'.$savename, 'w');
        if(!empty($this->header)){
            fputcsv($file,$this->header);
        }

        foreach($data as $value){
            fputcsv($file,$value);
        }
        fclose($file);
    }

    public function writeCSVDown($savename,$data){
        header("Content-Type: text/csv");
        header("Content-Disposition: attachment; filename=".$savename);
        header('Cache-Control:must-revalidate,post-check=0,pre-check=0');
        header('Expires:0');
        header('Pragma:public');
        $out = "";

        if(!empty($this->header)){
            foreach($this->header as $k => $value){
                $out .= $k?",".$value:$value;
            }
            $out .="\n";
        }

        foreach($data as $item){
            foreach($item as $k => $value){
                $out .= $k?",".$value:$value;
            }
            $out .="\n";
        }
        echo $out;
    }

    /**
     * 读取csv文件php5.3不兼容问题
     * @param $handle
     * @param null $length
     * @param string $d
     * @param string $e
     * @return bool
     */
    private function _fgetcsv(& $handle, $length = null, $d = ',', $e = '"') {
        if($this->php_low){
            $d = preg_quote($d);
            $e = preg_quote($e);
            $_line = "";
            $eof=false;
            while ($eof != true) {
                $_line .= (empty ($length) ? fgets($handle) : fgets($handle, $length));
                $itemcnt = preg_match_all('/' . $e . '/', $_line, $dummy);
                if ($itemcnt % 2 == 0)
                    $eof = true;
            }
            $_csv_line = preg_replace('/(?: |[ ])?$/', $d, trim($_line));
            $_csv_pattern = '/(' . $e . '[^' . $e . ']*(?:' . $e . $e . '[^' . $e . ']*)*' . $e . '|[^' . $d . ']*)' . $d . '/';
            preg_match_all($_csv_pattern, $_csv_line, $_csv_matches);
            $_csv_data = $_csv_matches[1];
            for ($_csv_i = 0; $_csv_i < count($_csv_data); $_csv_i++) {
                $_csv_data[$_csv_i] = preg_replace('/^' . $e . '(.*)' . $e . '$/s', '$1' , $_csv_data[$_csv_i]);
                $_csv_data[$_csv_i] = str_replace($e . $e, $e, $_csv_data[$_csv_i]);
            }
            return empty ($_line) ? false : $_csv_data;
        }else{
           return fgetcsv($handle,$length);
        }
    }

}

使用方法:更多用法看源码实现--代码通俗易懂^v^

一、读取上传文(用法1)---前端代码原生怎么写就怎么写

$csv = new CSV();
$csv->startRow = 1;
$csv->startColumn= 1;
$csv->importCSV();

二,读取上传文(用法2)

$config = array(
        'startRow'=>1,
        'startColumn'=>1,
        'trim'=> true
);
$csv = new CSV($config);
$csv->importCSV();

三、返回设置的key值下标数组--用于批量插入

$csv = new CSV();
$csv->keys= array('orderid','price','num','color');
$data = $csv->importCSV();

 

四、写一个CSV文件并下载(下面的二维数组数据---直接读取数据库的数据)

$data[] = array('yi','er','san');
$data[] = array('yi','er','san');
$csv = new CSV();
$csv->header = array('一','二','三');
$csv->writeCSVDown();

 最后寄语:

   不要动不动就问为什么不写成yii2组件,不为什么,框架只是一个代码规范而已,我喜欢yii2总体规范,但是不局限它,这就是原因,前进的动力。

       

如果文章对您有所帮助,希望继续支持我们,您的支持是我们最大的动力 ¥打赏
标签: CSV类 CSV批量导入数据 PHP批量导入数据 CSV文件操作
声明:文章内容由作者原创或整理,未经允许,不得转载!
您需要登录后才可以评论。登录 | 立即注册