所经历的大文件数据导出(后台执行,自动生成)

所经历的大文件数据导出(后台执行,自动生成)

http://www.cnblogs.com/fanfan259/p/4710019.html

阅读目录

一、前言

记录一下以前做的后台excel格式导出统计信息的功能,也是最近同事问到了相关东西,一时之间竟忘了具体的细节,因此记录一下;

大家知道,excel导出数据的功能,后台几乎是必须功能,一般都是点击后,生成文件然后自动下载,

如果是数据量小的话,一下子便可请求完成,从而下载到本地;

但是,如果数据量特别大的时候,页面就必须一直在等待,直到写入excel成功,

这样便影响了后台使用者无法操作其他页面,为此,对excel导出做了以下功能优化:

  1. excel导出分成两部分内容:生成excel文件和下载excel文件
  2. excel的文件生成在程序后台执行,前端不必等待,可进行其他后台操作
  3. 增加下载文件页面,显示excel文件生成的进度,完成后,方可下载生成的excel文件
  4. 文件生成后,点击下载方可下载相应的文件

二、生成excel文件

生成excel文件的方法有很多,暂不一一记录,只是记录本次的方法;

这里用到了table的html格式,以及相应的excel的声明

(隐约记得其他的方法用office07打开的时候好像是乱码,后面尝试用csv格式文件,可还是乱码,所以用了table的形式)

文件的开头:

 1     $struserdata = <<<Eof
 2         <html xmlns:o="urn:schemas-microsoft-com:office:office"
 3         xmlns:x="urn:schemas-microsoft-com:office:excel"
 4         xmlns="http://www.w3.org/TR/REC-html40">
 5
 6         <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 7         <html>
 8         <head>
 9             <meta http-equiv="Content-type" content="text/html;charset=utf-8" />
10         <style id="Classeur1_16681_Styles">
11         </style>
12         </head>
13         <body>
14         <div id="Classeur1_16681" align=center x:publishsource="Excel">
15
16         <table x:str border=1 cellpadding=0 cellspacing=0 width=100% style=‘border-collapse: collapse‘>
17 Eof;

文件的结尾:

1 $struserdata = <<<Eof
2         </table>
3         </div>
4         </body>
5         </html>
6 Eof;

当然,文件中间就是一些tr td 标签了。

三、让程序在后台执行

场景:

用户点击 生成excel后,跳转到下载页面,程序在后台执行,用户可不必等待生成完成,可执行其他操作;

下载页面可看到文件生成的进度以及是否可下载状态

思路:

点击 生成excel,显示下载页面  ---> show_download方法

生成excel ---> create_excel 方法

show_download方法中调用 create_excel方法,而show_download 方法中,自己用了一下命令行执行程序的方式,

利用php命令行的方式,把参数传递给 create_excel方法

1  // $cmd = "/usr/bin/php  /home/xxx/xxx.php " . $strjoin . "  >/dev/null & ";
2  // $a=exec($cmd, $out, $returndata);
3
4
5  $command = "/usr/bin/php ".STATISTIC_EXPORT_SCRIPT_DIR."xxx.php " . "‘" .$strjoin ."‘". " " . $uid . " ". $action ."  & ";
6  $process = proc_open($command, array(),$pipes);
7  $var = proc_get_status($process);
8  proc_close($process);
9  $pid = intval($var[‘pid‘])+1;

而在create_excel方法中:

需填写以下代码:

1 set_time_limit(0); //取消脚本运行时间的超时上限
2
3 ignore_user_abort(TRUE); //后台运行,不受用户关闭浏览器的影响

调用相关的api得到数据:

1 $statistic = call_user_func(array(‘shellscript‘,‘get_result‘),$url,$params);
2 if(!is_object($statistic) || !isset($statistic->data->items)){
3     usleep(400000);//停止400毫秒
4     $statistic = call_user_func(array(‘shellscript‘,‘get_result‘),$url,$params);
5 }

四、显示文件生成进度

但是怎么显示相应的文件生成进度呢,怎么知道文件到底生成好了没有呢?

这里,我用到的方法是,在写入数据文件的时候data.xsl,每个数据文件都生成一个对应的文件进度文件,暂且称为flag_data.xsl;

思路:

  1. 第一次请求api的时候,根据返回的total总数,以及pagesize,确定要请求的次数count;
  2. 这样便可知道要请求api的次数(分页请求api),在写入数据文件的同时,同时写入进度文件flag_data.xsl;   
    数据格式大约是(以逗号分割)
        1,5
        2,5
        ...
  3. 然后显示文件进度的时候,读取进度文件,这样变可知道数据文件大体的进度
  4. 前端js处理时,几秒读取一次相应的方法(如果都100%进度,可停止请求方法),从而实现动态查看文件的生成进度

查看文件的进度方法:

 

五、下载文件

文件的下载就好说了,既然已经都生成成功,下载的方法如下:

 1     public function execscript_download(){
 2         $filename = $_REQUEST[‘filename‘];
 3         $uid = $_REQUEST[‘uid‘];
 4         $file_dir = STATISTIC_EXPORT_FILE_DIR.$uid.‘/‘.$filename;
 5         if (!file_exists($file_dir)){
 6             header("Content-type: text/html; charset=utf-8");
 7             echo "File not found!";
 8             exit;
 9         } else {
10             ini_set("memory_limit","500M");
11             header(‘Content-Description: File Transfer‘);
12             header(‘Content-Type: application/octet-stream‘);
13             header(‘Content-Disposition: attachment; filename=‘.basename($file_dir));
14             header(‘Content-Transfer-Encoding: binary‘);
15             header(‘Expires: ‘ . gmdate(‘D, d M Y H:i:s‘) . ‘ GMT‘);
16             header(‘Cache-Control: must-revalidate,post-check=0, pre-check=0‘);
17             header(‘Pragma: public‘);
18             header(‘Content-Length: ‘ . filesize($file_dir));
19             readfile($file_dir);
20         }
21
22     }

六、上线后出现的问题

本地本来已经测试完毕,可上线后,却出现了奇怪的问题;

现象描述:

当在后台点击生成文件,跳转到下载页的时候,因为下载页是显示文件进度的页面,
        竟然出现有时候有刚刚点击的文件进度,有时候没有,就感觉没有生成相应的文件一样;

解决方法:

因为数据文件和进度文件都是生成在程序的某个文件夹file中,所以读取的时候都是读取的文件夹下的文件,从而判断显示进度;

后面才知道,由于后台程序有两台服务器,导致读取以及下载的时候找不到相应的文件夹,两个服务器相应的文件夹弄个共享目录就可以了

七、相应的后续优化

由于下载的文件多了,导致文件夹下的文件越来越多,而原来生成的文件是没有价值的,所以加了个定期删除文件的功能,只保留近七天的文件

当然可以用crontab,只不过我比较懒,是在点击生成文件的时候,判断了一下文件夹中的过期文件,从而删除

 1     public function execscript_process_show(){
 2         $this->load->library(‘smarty‘);
 3         $uid = $_REQUEST[‘uid‘];
 4         $url_dir = STATISTIC_EXPORT_FILE_DIR.$uid .‘/‘;//@todo
 5         if(!is_dir($url_dir)){
 6             @mkdir($url_dir,0777);
 7         }
 8         $files = scandir($url_dir);
 9         if(!empty($files)){
10             foreach ($files as $key => $value) {
11                 if($value!=‘.‘ && $value!=‘..‘){
12                     foreach ($files as $key => $value) {
13                         if($value!=‘.‘ && $value!=‘..‘){
14                             if(substr($value, 0 , 5)!="flag_"){
15                                 $filenamedate = substr($value, 0,10);
16                                 $today = date(‘Y-m-d‘,time());
17                                 $filenamedate = date(‘Y-m-d‘,strtotime($filenamedate)+(STATISTIC_FILE_EXPIRE_DAY-1)*24*3600);
18                                 if($today>$filenamedate){//文件过期
19                                     @unlink($url_dir . $value);
20                                     @unlink($url_dir . ‘flag_‘ . $value);
21                                 }
22                             }
23                         }
24                     }
25                 }
26             }
27         }
28
29         $this->smarty->assign(‘uid‘,$uid);
30         $this->smarty->display(‘interact/statistic/execscript.tpl‘);
31     }

八、后记

大文件的导出大体就是这个样子,欢迎大家吐槽,共同交流;

当时在用命令行执行方法的时候,也参考了一下相应的资料,记录一下;

http://blog.csdn.net/yysdsyl/article/details/4636457

http://www.codesky.net/article/201202/163385.html

http://www.cnblogs.com/zdz8207/p/3765567.html

http://blog.163.com/[email protected]/blog/static/4112219320097300922992/

http://php.net/manual/en/features.commandline.php

http://blog.csdn.net/yangjun07167/article/details/5603425

http://blog.csdn.net/yunsongice/article/details/5445448

http://www.cppblog.com/amazon/archive/2011/12/01/161281.aspx

http://blog.51yip.com/tag/proc_open

http://www.justwinit.cn/post/1418/

http://limboy.me/tech/2010/12/05/php-async.html

时间: 2024-09-28 20:05:41

所经历的大文件数据导出(后台执行,自动生成)的相关文章

大文件/数据网络传输方法总结(转载)

网络编程中不免会遇到需要传输大数据.大文件的情况,而由于socket本身缓冲区的限制,大概一次只能发送4K左右的数据,所以在传输大数据时客户端就需要进行分包,在目的地重新组包.而实际上已有一些消息/通讯中间件对此进行了封装,提供了直接发送大数据/文件的接口:除此之外,利用共享目录,ftp,ssh等系统命令来实现大文件/数据也不失为一种好的方法. 1.基础的基于socket进行传输 基础的基于socket进行传输关键在于控制,需要自己行分包和组包. ////////////////////////

关于后台系统自动生成的一点思考

大量实践发现后台管理程序,其实90%的代码都是相同的,当然是在抛弃复杂逻辑业务的情况下,那么如何能高效的节约这些时间呢,那就是接下来我要说的,对于后台系统自动生成的一些思考. 适用情景: 1.表编号id为自增(基于现在大部分表编号都是自增的情况): 2.没有太复杂业务关联关系,比如表的某一个字段,存储了一个json对象,为了平衡后台用户使用,需要友好的分段展示给用户的定制ui界面:还比如表中存储了外键的多个id,但为了方便用户使用,只能已标签name的方式,给用户展示,等等这些超强业务黏合逻辑的

PHP几个几十个G大文件数据统计并且排序处理

诸多大互联网公司的面试都会有这么个问题,有个4G的文件,如何用只有1G内存的机器去计算文件中出现次数最多的数字(假设1行是1个数组,例如QQ号 码).如果这个文件只有4B或者几十兆,那么最简单的办法就是直接读取这个文件后进行分析统计.但是这个是4G的文件,当然也可能是几十G甚至几百G的文 件,这就不是直接读取能解决了的. 同样对于如此大的文件,单纯用PHP做是肯定行不通的,我的思路是不管多大文件,首先要切割为多个应用可以承受的小文件,然后批量或者依次分析统计小文件后再把总的结果汇总后统计出符合要

PHPUnit-函数依赖-数据提供-异常-忽略-自动生成

本文目的 本文目的是收录一些PHPUnit的有用技巧,这些技巧能够为给PHPUnit单元测试带来很多便利.本文将要介绍的技巧如下: 函数依赖测试 数据提供函数 异常测试 跳过忽略测试 自动生成测试框架 函数依赖测试 有时候,类中的函数有依赖,而且你的逻辑需要被依赖函数正确执行,此时,你可以通过phpunit的依赖标签显示的标明这种依赖关系,如果任意被依赖的函数执行失败,那么依赖函数将会被自动跳过.如下所示代码(dependenceDemo.cpp): 1 <?php 2 class Depend

用php导入10W条+ 级别的csv大文件数据到mysql。导出10W+级别数据到csv文件

转自:http://blog.csdn.net/think2me/article/details/12999907 1. 说说csv 和 Excel 这两者都是我们平时导出或者导入数据一般用到的载体.两者有什么区别呢?csv 格式更兼容一点.那么共同点都是GBK格式的,非UTF8.所以我们上传文件的时候,老是出现乱码,就是编码问题没有转好导致. 2. 推荐的几种方法 1. 函数 fgetss($handel);  返回字符串.它就是strip_tags(fget($handel))的组合读取cs

Sybase IQ如何将大文件数据迅速加载到数据库

试想一下,如果一个文件5G.10G甚至更大.如何将它迅速地加载到数据库指定的表呢?我们看看Sybase IQ是如何迅速地将表的数据加载到数据库的. 数据文件格式: 1440,2011-01-09 00:00:00,1,珠海,1,C网,8612345678222,221943,1,12175,1,12,14426467,1191632,9,1440,2011-01-09 00:00:00,1,珠海,1,C网,8612345678222,968852,1,82077,1,7,2430696,1349

csv文件数据导出到mongo数据库

from pymongo import MongoClientimport csv# 创建连接MongoDB数据库函数def connection(): # 1:连接本地MongoDB数据库服务 conn=MongoClient("localhost",27017) # 2:连接本地数据库(guazidata).没有时会自动创建 db=conn.python # 3:创建集合 set1=db.data # 4:授权 db.authenticate(name='zhaochuan', p

如何实现大文件数据上传

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms; namespace WinShowDown{ public partial class FrmMain : Form { public FrmMa

如何将sqlserver表中的数据导出sql语句或生成insert into语句 [转]

输入表名,生成插入语句 drop proc proc_insert //如果存在就删除 go create proc proc_insert (@tablename varchar(256)) as begin set nocount on declare @sqlstr varchar(4000) declare @sqlstr1 varchar(4000) declare @sqlstr2 varchar(4000) select @sqlstr='select ''insert '[ema