我一直在寻找如何在一行中查找值并返回 CSV 文件中另一列的值。
这是我的函数,它工作正常,但在小文件中:
function find_user($filename, $id) {
$f = fopen($filename, "r");
$result = false;
while ($row = fgetcsv($f, 0, ";")) {
if ($row[6] == $id) {
$result = $row[5];
break;
}
}
fclose($f);
return $result;
}
问题是我必须使用的实际文件大小为 4GB。而且搜索所花费的时间是巨大的。
浏览 Stack Overflow,我发现了以下帖子: file_get_contents => PHP Fatal error: Allowed memory exhausted
他们为我提供了以下功能(根据我的理解),使我可以更轻松地搜索巨大的 CSV 值:
function file_get_contents_chunked($file,$chunk_size,$callback)
{
try
{
$handle = fopen($file, "r");
$i = 0;
while (!feof($handle))
{
call_user_func_array($callback,array(fread($handle,$chunk_size),&$handle,$i));
$i++;
}
fclose($handle);
}
catch(Exception $e)
{
trigger_error("file_get_contents_chunked::" . $e->getMessage(),E_USER_NOTICE);
return false;
}
return true;
}
使用方法似乎如下:
$success = file_get_contents_chunked("my/large/file",4096,function($chunk,&$handle,$iteration){
/*
* Do what you will with the {&chunk} here
* {$handle} is passed in case you want to seek
** to different parts of the file
* {$iteration} is the section fo the file that has been read so
* ($i * 4096) is your current offset within the file.
*/
});
if(!$success)
{
//It Failed
}
问题是我不知道如何调整我的初始代码以与提出的函数配合使用以加快大型 CSV 中的搜索速度。我对 PHP 的了解不是很深入。
最佳答案
无论您如何阅读文件,都无法加快搜索速度,因为您在搜索正确的行和列时始终必须扫描每个字符。最坏的情况是您要查找的行是文件中的最后一行。
您应该将 CSV 导入适当的索引数据库,并修改您的应用程序以进一步将新记录保存到该数据库而不是 CSV 文件。
这是一个使用 SQLite 的基本示例。我创建了一个包含 1 亿条记录 (~5GB) 的 CSV 文件并对其进行了测试。
创建 SQLite 数据库并将 CSV 文件导入其中:
$f = fopen('db.csv', 'r');
$db = new SQLite3('data.db');
$db->exec('CREATE TABLE "user" ("id" INT PRIMARY KEY, "name" TEXT,
"c1" TEXT, "c2" TEXT, "c3" TEXT, "c4" TEXT, "c5" TEXT)');
$stmt = $db->prepare('INSERT INTO "user"
("id", "name", "c1", "c2", "c3", "c4", "c5") VALUES (?, ?, ?, ?, ?, ?, ?)');
$stmt->bindParam(1, $id, SQLITE3_INTEGER);
$stmt->bindParam(2, $name, SQLITE3_TEXT);
$stmt->bindParam(3, $c1, SQLITE3_TEXT);
$stmt->bindParam(4, $c2, SQLITE3_TEXT);
$stmt->bindParam(5, $c3, SQLITE3_TEXT);
$stmt->bindParam(6, $c4, SQLITE3_TEXT);
$stmt->bindParam(7, $c5, SQLITE3_TEXT);
$db->exec('BEGIN TRANSACTION');
while ($row = fgetcsv($f, 0, ';')) {
list($c1, $c2, $c3, $c4, $c5, $name, $id) = $row;
$stmt->execute();
}
$db->exec('COMMIT');
这需要很长时间,在我的计算机上超过 15 分钟,生成了 6.5GB 的文件。
从数据库中搜索:
$id = 99999999;
$db = new SQLite3('data.db');
$stmt = $db->prepare('SELECT "name" FROM "user" WHERE "id" = ?');
$stmt->bindValue(1, $id, SQLITE3_INTEGER);
$result = $stmt->execute();
print_r($result->fetchArray());
这几乎是立即执行的。
关于php - 在 PHP 中短时间内解析大型 CSV 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45911371/