我创建了这个php脚本,它需要很长时间才能将CSV文件过滤成19个较小的文件。CSV的链接是在这个谷歌驱动器行
https://drive.google.com/drive/folders/1Bju4kkVgo21xu3IFeyKWNJ1uClTn534J?usp=share_link
我让进程逐行运行以保存内存,但这超过了PHP脚本中的最大计数时间。是否有改进的方法来实现此文件分解?
<?php
@date_default_timezone_set("GMT");
ini_set('memory_limit', '512M');
ini_set('max_execution_time', '300');
ini_set('auto_detect_line_endings', TRUE);
ini_set('display_errors', 1);
$inputFile = '/Users/declanryan/Desktop/UNI3.0/year3/WEB/workshop/assgienment/air-quality-data-2003-2022.csv';
$outputDirectory = 'output';
// create the output directory if it doesn't exist
if (!file_exists($outputDirectory)) {
mkdir($outputDirectory);
}
$handle = fopen($inputFile, 'r');
if ($handle) {
$headerRow = null;
$siteIDs = array();
while (($data = fgets($handle)) !== false) {
$row = str_getcsv($data, ";");
if ($headerRow === null) {
$headerRow = $row;
continue; // Skip processing the header row
}
$siteID = $row[array_search('SiteID', $headerRow)];
if (!in_array($siteID, $siteIDs)) {
$siteIDs[] = $siteID;
$newCSVFilename = $outputDirectory . '/data-' . $siteID . '.csv';
$f = fopen($newCSVFilename, 'w');
fputs($f, implode(';', $headerRow) . PHP_EOL);
}
$currentCSVFilename = $outputDirectory . '/data-' . $siteID . '.csv';
$f = fopen($currentCSVFilename, 'a');
fputs($f, implode(';', $row) . PHP_EOL);
fclose($f);
}
fclose($handle);
}
echo "Done.";
echo "<br>";
echo 'Script took ' . round((microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"]), 2) . ' seconds to run.';
?>
它已经花了足够的时间,甚至得到文件处理发生。我本来想把格式改成getcsv,但是我的讲座告诉我这种方法实际上比较慢?
作为对Sammath回答,像这样的东西是否更符合必要性?
@date_default_timezone_set("GMT");
ini_set('memory_limit', '512M');
ini_set('max_execution_time', '300');
ini_set('auto_detect_line_endings', TRUE);
ini_set('display_errors', 1);
$inputFile = '/Users/declanryan/Desktop/UNI3.0/year3/WEB/workshop/assgienment/air-quality-data-2003-2022.csv';
$outputDirectory = 'output';
// create the output directory if it doesn't exist
if (!file_exists($outputDirectory)) {
mkdir($outputDirectory);
}
$source = fopen($inputFile, 'r');
if (!$source) {
exit('Unable to open input file.');
}
$headerRow = fgetcsv($source, 0, ';');
if (!$headerRow) {
exit('Unable to read header row.');
}
$columnIndexes = array_flip($headerRow);
$siteIDColumn = $columnIndexes['SiteID'];
$handles = [];
while (($row = fgetcsv($source, 0, ';')) !== false) {
$siteID = $row[$siteIDColumn];
if (!isset($handles[$siteID])) {
$newCSVFilename = $outputDirectory . '/data-' . $siteID . '.csv';
$handles[$siteID] = fopen($newCSVFilename, 'w');
if (!$handles[$siteID]) {
exit('Unable to open output file for SiteID: ' . $siteID);
}
fputcsv($handles[$siteID], $headerRow, ';');
}
fputcsv($handles[$siteID], $row, ';');
}
foreach ($handles as $handle) {
fclose($handle);
}
fclose($source);
echo "Done.";
echo "<br>";
echo 'Script took ' . round((microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"]), 2) . ' seconds to run.';
2条答案
按热度按时间tktrz96b1#
接触文件系统有一个不平凡的数量最慢的IO计算机通常做,PHP抽象了很多优化。但是,当你反复打开一个文件,写入非常少量的数据,然后关闭它时,你不仅使这些优化毫无意义,而且还做了你能做的最糟糕的事情:不断刷新磁盘上的微小写入。
对于这样的东西,你应该打开这些句柄 * 一次 *,它可能看起来大致如下:
此外,
fgetcsv()
和str_getcsv(fgets())
在功能上几乎没有区别,但是implode(';', $row)
不是一个合适的CSV编码方法,因为它不会执行任何字符串引用/转义等。tvokkenx2#
您的执行时间有三个来源:
例如:
yields(在我的系统上):
我用不同的BUFFERSIZE做了一些实验(报告的内存是脚本已经分配的内存之外的内存)。
注意可变性(我可能应该重新启动或至少运行
sync
并在测试之间该高速缓存),以及它不需要太多缓冲来提高速度的事实(在某个点之后,效率将再次开始下降,因为PHP正在努力处理非常大的字符串连接)。缓冲区的实际大小取决于底层文件系统:如果它是缓存支持的,就像我的一样,那么很可能大的BUFFERSIZE不会有太大的改变。