最近我同事做了一个PHP项目,其中有一个功能是 上传excel文件并将数据导入mongodb某个集合中。

通常的做法是 写一个上传文件的页面,然后后端 读取 这个文件,利用phpexcel类库将这个excel文件中的数据读入到某个数组中,

然后循环写入monogodb的某个集合中。 经过实践成功搞定。文件小的时候一切OK,但是当上传的文件很大的时候,或者说数据量很大的时候,

上面的办法就发生问题了。有时候后端没有响应,有时候可以成功,但是一般需要很长的时间才能完成任务。

我们这边测试一下,上传一个33万行*15列的数据量,大概有40M的文件,基本上是无法成功导入。

无法成功的原因 初步估计为phpexcel类库的原因,

网上说 一个单元格大致需要1K的内存,所以可能会引起内存分配不够的错误。

还有个问题是如果是导入2007版的excel的时候,利用php函数simplexml_load_string的时候就已经发生错误了。

有兴趣的朋友可以 去看一下PHPExcel\PHPExcel\Reader\Excel2007.php 里面的load方法。

为此 我们做了一些尝试

1 ini_set('memory_limit', '1G');//适当放大脚本执行内存的限制

2 set_time_limit(0);//不要让脚本过期

3 将文件压缩之后上传,然后在后端解压之后,在处理。

4 根据http://phpexcel.codeplex.com/discussions/242712 这个指示改写了程序

5 放弃使用phpexcel改用其他的excel类库。

尝试的结果 都不成功。

后来想 要不将excel文件改成csv文件 是否可行。尝试如下

将那个40M的文件先手工方式 转换成csv文件,上传该文件。

尝试1:

利用phpexcel读取文件内容

结果如下:

发生了错误,原来phpexcel中其实没有专门处理csv文件的类。

尝试2:

改用php原生的文件读取函数fgetcsv()。

结果如下:

成功导入,但是性能很差,处理的时间很长,大概需要30分钟。客户无法忍受。

最后 利用mongodb自带的mongoimport工具可以上传csv文件

命令如下

mongoimport -h localhost --port 27017 -d test222 -c c21 -f REG,PROV,CITY,STORE,CHN,ACCOUNTREF_CD,ACCOUNTTYPE,KEY_CUST,PDT_CAT,SKU_CD,PDT_NAME,CAL_MON_CD,CAL_WEEK_CD,DT_ID,OS,OOS,VOID --ignoreBlanks --file "D:\phpworkspace\importData\public\phpexcel\RTX_NON_COMP_OSA3.csv" --type csv

执行结果,让人兴奋不已,不到1分钟的时间就导入成功。

由此,我们想到了一个办法,可不可以利用 php的函数system ()或exec()命令执行mongoimport命令

经过尝试,发现是可行的,但是只能以 php xxx.php的方式才能运行而不能用http://xxx/xxx.php方式。可能跟执行权限有关吧。

所以调整思路

1 创建一个uploadfile.php文件,专门处理网页上上传文件,将上传的文件,放入指定的某个目录中

2 创建一个loaddatatomongo.php文件,专门利用php的函数system ()或exec()命令执行mongoimport命令,

  将那个目录下的文件内容导入到mongodb的集合中,并在处理完成之后,将该文件删除。

3 将第2步所建立的php文件通过计划任务来执行。crontab 中增加 php loaddatatomongo.php 命令

经过一番的折腾,终于成功实现了在很短的时间将csv文件内容导入到mongo中去。

这个过程中发生了一下的问题汇总如下

1 mongoimport 导入csv文件的时候,这个csv文件必须是utf8编码方式的,否则无法导入

通过运用调用linux命令 /usr/bin/iconv -t UTF-8 文件a.csv -o 文件b.csv 解决

2  上传的文件是zip压缩的文件,需要需要一个解压的命令

通过运用调用linux命令 unzip  文件.zip 解决

3 在linux系统中直接执行运行 php loaddatatomongo.php 可以成功转换,而通过计划任务执行的时候,却始终不成功

新建一个shell执行文件,比如说 ss.sh,将crontab计划任务表中 php loaddatatomongo.php 的部分,改成 ss.sh

然后将 php loaddatatomongo.php 命令放在这个shell脚本,最后在这个shell脚本里面头上增加export LANG=zh_CN.GB18030命令

php部的源代码发布出来,以供参考

//读取文件信息

$arrayFileInfo = get_headers($arrayExcel['file']);

$strZipName = uniqid().'.zip';
$file = file_get_contents($arrayExcel['file']);
$strCsvNow = substr($arrayExcel['name'], 0,-3).'csv';
$strCsvNow2 = 'new'.substr($arrayExcel['name'], 0,-3).'csv';
$tmpfname = APPLICATION_PATH.'/../cache/'.$strZipName;
file_put_contents($tmpfname, $file); //写入临时ZIP文件

//文件解压命令
$strVim0 = 'unzip '.$tmpfname;

//utf8转换命令
$strVim1 = '/usr/bin/iconv -t UTF-8 '.$strCsvNow.' -o '.$strCsvNow2;

//构造mongoimport命令
$strVim2 = '/usr/local/mongodb/bin/mongoimport -h 10.0.0.31 --port 27017 -d umav3 -c '.$strCollect.' -f ';
$arrayRemoveQuery = array();
foreach ($arrayStructure as $key => $val)
{
if($key <2)
$arrayRemoveQuery[$val['alias']] = $val['name'];
$strVim2.= $val['alias'].',';
}
$strVim2 = substr($strVim2, 0,-1);
$strVim2.=' --ignoreBlanks --file '.$strCsvNow2.' --type csv';

//执行命令
system($strVim0,$retval1);
system($strVim1,$retval2);
system($strVim2,$retval3);

//文件删除
unlink($strZipName);
unlink($strCsvNow);
unlink($strCsvNow2);

利用mongoimport命令导入csv大文件的更多相关文章

  1. PHP读取CSV大文件导入数据库的示例

    对于数百万条数据量的CSV文件,文件大小可能达到数百M,如果简单读取的话很可能出现超时或者卡死的现象. 为了成功将CSV文件里的数据导入数据库,分批处理是非常必要的. 下面这个函数是读取CSV文件中指 ...

  2. MYSQL导入CSV格式文件数据执行提示错误(ERROR 1290): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement.

    MYSQL导入CSV格式文件数据执行提示错误(ERROR 1290): The MySQL server is running with the --secure-file-priv option s ...

  3. PHP快速按行读取CSV大文件的封装类分享(也适用于其它超大文本文件)

    CSV大文件的读取已经在前面讲述过了(PHP按行读取.处理较大CSV文件的代码实例),但是如何快速完整的操作大文件仍然还存在一些问题. 1.如何快速获取CSV大文件的总行数? 办法一:直接获取文件内容 ...

  4. mysql导入csv格式文件

    今天测试导入csv格式文件,虽然简单但是如果不注意还是会出现错误,而且mysql在某些方面做的确实对新手不是很友好,记录一下:创建一个csv格式文件:[mysql@xxx1 ycrdb]$ more ...

  5. 使用dd命令快速生成大文件或者小文件的方法

    使用dd命令快速生成大文件或者小文件的方法     转载请说明出处:http://blog.csdn.net/cywosp/article/details/9674757     在程序的测试中有些场 ...

  6. 使用dd命令快速生成大文件或者小文件

    使用dd命令快速生成大文件或者小文件 需求场景: 在程序的测试中有些场景需要大量的小文件或者几个比较大的文件,而在我们的文件系统里一时无法找到那么多或者那么大的文件,此时linux的dd命令就能快速的 ...

  7. csv大文件分割以及添加表头

    注:这里说的大文件也不是太大,只有60多M而已(70多万条数据),相对比较大而已. 为了减轻编辑的工作,某种情况下网站上可能用会到csv格式的文件进行数据导入,但一般网站除了有上传文件大小限制以外,还 ...

  8. Linux下的split 命令(将一个大文件根据行数平均分成若干个小文件)

    将一个大文件分成若干个小文件方法 例如将一个BLM.txt文件分成前缀为 BLM_ 的1000个小文件,后缀为系数形式,且后缀为4位数字形式 先利用 wc -l BLM.txt       读出 BL ...

  9. linux使用dd命令快速生成大文件

    dd命令可以轻易实现创建指定大小的文件,如 dd if=/dev/zero of=test bs=1M count=1000 会生成一个1000M的test文件,文件内容为全0(因从/dev/zero ...

随机推荐

  1. Java---练习(面试题) :字符串截取(1)

    在java中,字符串"abcd"与字符串"ab你好"的长度是一样,都是四个字符. 但对应的字节数不同,一个汉字占两个字节. 定义一个方法,按照指定的字节数来取子 ...

  2. Linux 上使用 Gmail SMTP 服务器发送邮件通知

    导读 假定你想配置一个 Linux 应用,用于从你的服务器或桌面客户端发送邮件信息.邮件信息可能是邮件简报.状态更新(如 Cachet).监控警报(如 Monit).磁盘时间(如 RAID mdadm ...

  3. Java程序员需要注意的五大Docker误区

    Docker现在很火,容器技术看上不无所不能,但这实际上是一种误解,不要被炒作出来的泡沫迷住双眼,本文抛去炒作,理性地从Java程序员的角度,列举出Docker目前的五大误区,帮助你更好地理解Dock ...

  4. php几个不起眼儿的小技巧

    说是不起眼儿的小技巧,其实应该说是不常用的常规应用吧.很多事情就是这样,知道是一马事儿,会用是一马事儿,精习又是另外一马事儿.而成为高手更是需要扎实的基本功. str_repeat 重复输出字符串就靠 ...

  5. swift - if let Optional 语法

    var optionalString: String? = "facial"; var greeting = "hi"; if let name = optio ...

  6. unix网络编程第三版源代码ubuntu下配置的问题解决

    第一步:首先下载本书配套的源码unpv13e.tar.gz 第二步:解压后进入根文件夹有一个README 4 Execute the following from the src/ directory ...

  7. poj2096 Collecting Bugs(概率dp)

    Collecting Bugs Time Limit: 10000MS   Memory Limit: 64000K Total Submissions: 1792   Accepted: 832 C ...

  8. CentOS 6.3下部署LVS(NAT)+keepalived实现高性能高可用负载均衡【转】

    CentOS 6.3下部署LVS(NAT)+keepalived实现高性能高可用负载均衡   一.简介 VS/NAT原理图: 二.系统环境 实验拓扑: 系统平台:CentOS 6.3 Kernel:2 ...

  9. Ubuntu启动时直接进入命令行模式

    直接粘命令吧 sudo vim /etc/init/lightdm.conf 注释掉下面的内容 start on ((filesystem and runlevel [!06] and started ...

  10. LVM命令摘要

      命令 描述 物理卷(PV) pvcreate 创建LVM磁盘     #pvcreate /dev/sdb pvdisplay 显示卷组中的物理卷信息 pvchange 设置PV的性能,允许或拒绝 ...