好的,我有一个按钮。当按下时,它会这样做:
Javascript
$("#csv_dedupe").live("click", function(e) {
file_name = 'C:\server\xampp\htdocs\Gene\IMEXporter\include\files\' + $("#IMEXp_import_var-uploadFile-file").val();
$.post($_CFG_PROCESSORFILE, {"task": "csv_dupe", "file_name": file_name}, function(data) {
alert(data);
}, "json")
});
这个ajax调用被发送到:
PHP
class ColumnCompare {
function __construct($column) {
$this->column = $column;
}
function compare($a, $b) {
if ($a[$this->column] == $b[$this->column]) {
return 0;
}
return ($a[$this->column] < $b[$this->column]) ? -1 : 1;
}
}
if ($task == "csv_dupe") {
$file_name = $_REQUEST["file_name"];
// Hard-coded input
$array_var = array();
$sort_by_col = 9999;
//Open csv file and dump contents
if(($handler = fopen($file_name, "r")) !== FALSE) {
while(($csv_handler = fgetcsv($handler, 0, ",")) !== FALSE) {
$array_var[] = $csv_handler;
}
}
fclose($handler);
//copy original csv data array to be compared later
$array_var2 = $array_var;
//Find email column
$new = array();
$new = $array_var[0];
$findme = 'email';
$counter = 0;
foreach($new as $key) {
$pos = strpos($key, $findme);
if($pos === false) {
$counter++;
}
else {
$sort_by_col = $counter;
}
}
if($sort_by_col === 999) {
echo 'COULD NOT FIND EMAIL COLUMN';
return;
}
//Temporarily remove headers from array
$headers = array_shift($array_var);
// Create object for sorting by a particular column
$obj = new ColumnCompare($sort_by_col);
usort($array_var, array($obj, 'compare'));
// Remove Duplicates from a coulmn
array_unshift($array_var, $headers);
$newArr = array();
foreach ($array_var as $val) {
$newArr[$val[$sort_by_col]] = $val;
}
$array_var = array_values($newArr);
//Write CSV to standard output
$sout = fopen($file_name, 'w');
foreach ($array_var as $fields) {
fputcsv($sout, $fields);
}
fclose($sout);
//How many dupes were there?
$number = count($array_var2) - count($array_var);
echo json_encode($number);
}
这个php从csv文件中获取所有数据。列和行,并使用fgetcsv函数将所有数据分配给一个数组。现在我有了代码,它还通过单列对csv文件进行重复数据消除(查找并删除重复文件的副本)。保持整个数组的行和列结构不变。
唯一的问题是,即使它适用于我测试的大约有10行的小文件,但它不适用于25000行的文件。
现在,在你说之前,我已经进入了我的php.ini文件,并将max_input、filesize、max time running等更改为天文数字,以确保php可以接受高达999999999999999 MB的文件大小和几百年的脚本运行时间。
我使用了一个包含25000条记录的文件并执行了脚本。两个小时过去了,fiddler仍然显示http请求尚未返回。有人能给我一些优化服务器和代码的方法吗?
我能够使用一位用户的代码,他在我发布的另一个问题中帮助了我,甚至在最初如何做到这一点。我现在担心的是,即使我对它进行了测试,我也想知道如何在不到一分钟的时间内使它发挥作用。Excel可以在几秒钟内消除一列一百万条记录的重复数据,为什么php不能做到这一点?
Sophie,我想你在编写这种类型的应用程序方面没有经验,因为IMO这不是解决这个问题的方法。所以我会相应地推销这个。
当你遇到这样的性能问题时,你真的需要对问题进行二进制处理,以了解发生了什么。因此,第1步是将PHP时序问题与AJAX解耦,并简单地理解为什么你的方法如此无响应。使用本地安装的PHP cgi,甚至使用您的web安装并发布一个标题("Contentxt-Type:text/plain"),并转储每个步骤的微时间。CSV读取需要多长时间,排序、结节、写入都需要多长时间?对每次行数增加10倍的CSV文件大小范围执行此操作。
还要在每一步执行memory_get_usage(),看看您是如何消耗内存的。因为你的方法是一个真正的猪,你可能会因为达到配置的内存限制而出错——phpinfo()会告诉你这些。
读、结和写都是o(N),但排序最好是o(NlogN),最坏是o(N+sup>2)。您的排序还在每次比较中调用一个PHP方法,因此速度会很慢。
我不明白的是,你为什么要进行排序,因为你的结节算法没有利用行已经排序的事实。
(顺便说一句,排序也会对标题行进行内联排序,所以如果你仍然想进行排序,你需要在之前取消对其进行移位。)
你还需要考虑其他问题,比如
-
使用原始参数作为文件名会使您容易受到攻击。最好相对于DOCROOT/Gene/IMEXporter/include修复补丁,并对文件名强制执行一些语法。
-
您需要考虑读取和重写大文件作为对web请求的响应的原子性——如果两个客户端同时发出请求,会发生什么。
-
最后,将其与Excel进行比较,加载和保存Excel文件可能需要时间,并且Excel不必同时扩展到10秒或100秒或用户。在事务系统中,你通常使用D/B后端来处理这类事情,如果你使用web界面来计算繁重的任务,你需要接受Apache(或等效服务器)的硬内存和时间限制,并相应地修改你的算法和方法。