У меня есть несколько больших файлов CSV, которые содержат примерно 285 столбцов.
Между файлами более миллиона строк.
Для разбора каждой строки я использую fgets
который работает быстро.
Оттуда я попытался использовать str_getcsv
на линии, что в среднем составляет 0,001421 секунды на строку. Звучит не так много, но если вы наберете 1 000 000 строк, это 1421 секунда или примерно 24 минуты.
Чтобы ускорить процесс, я делаю как можно больше сравнения со строками, прежде чем пытаться проанализировать CSV. Если мои чеки считают это неуместным, то пропускает строку.
Моя проблема возникает, когда мне нужны индексированные значения для более сложного сравнения данных.
Является str_getcsv
самый быстрый вариант, или есть более быстрый способ получить строки в массив?
Моей первой мыслью было использовать explode, но данные содержат значения в кавычках, а некоторые значения также содержат запятые.
Мне нужно работать только с одной строкой за раз, если это помогает с правилами синтаксического анализа.
Я закончил тем, что создал решение для себя, но мне любопытно, может ли кто-нибудь еще проверить это с большим набором данных?
Разбор строк с использованием str_getcsv
в результате в среднем 0,0014 секунд.
В результате синтаксического анализа с этим кодом в среднем было 0,0002 секунды.
Это определенно может использовать дополнительную работу для обеспечения большей гибкости, но ради простого CSV с указанными значениями, это прекрасно работает для моих целей.
function _csv2array($line) {
$ret = [0 => '']; //Start with an empty array
$idx = 0; //First index
$lastpos = 0; //No commas found yet
while (($pos = strpos($line, ',', $lastpos)) !== FALSE) { //While we find another comma
$ret[$idx].= substr($line, $lastpos, $pos-$lastpos); //Add it to our current index
if (substr($ret[$idx], 0, 1) == '"') { //If we started with a quote
if (substr($ret[$idx], -1) == '"') { //Are we ending in a quote?
$qts = substr_count($ret[$idx], '"') % 2; //Are there an even number of quotes?
if (!$qts) { //If there's an even amount of quotes, safe to close out this field
$ret[$idx] = trim($ret[$idx], '"'); //Remove the outer quotes
$ret[++$idx] = ''; //Start the next index
} else $ret[$idx].= ','; //Still inside a quoted field, don't ignore this comma, append it
} else $ret[$idx].= ','; //Still inside a quoted field, don't ignore this comma, append it
} else { //Non quoted field
$ret[++$idx] = ''; //Advance to next index
}
$lastpos = $pos+1; //Start our next search AFTER this comma
}
$ret[$idx].= substr($line, $lastpos); //Add whatever's after the last ,
$ret[$idx] = trim($ret[$idx], "\"\r\n"); //Remove any newlines/surrounding quotes
return $ret; //Return the array
}
Других решений пока нет …