PHP 已经提供了一种使用 SplFileObject 以 OO 方式读取 CSV 文件的方法:
$file = new SplFileObject("data.csv");
// tell object that it is reading a CSV file
$file->setFlags(SplFileObject::READ_CSV);
$file->setCsvControl(',', '"', '\\');
// iterate over the data
foreach ($file as $row) {
list ($fruit, $quantity) = $row;
// Do something with values
}
由于 SplFileObject 流过 CSV 数据,因此内存消耗非常低,您可以有效地处理大型 CSV 文件,但由于是文件 i/o,它并不是最快的。但是,SplFileObject 实现了 Iterator 接口,因此您可以将该 $file 实例包装到其他迭代器中以修改迭代。例如,要限制文件 i/o,您可以将其包装到 CachingIterator 中:
$cachedFile = new CachingIterator($file, CachingIterator::FULL_CACHE);
要填充缓存,您需要遍历 $cachedFile。这将填充缓存
foreach ($cachedFile as $row) {
然后迭代缓存,你做
foreach ($cachedFile->getCache() as $row) {
权衡显然是增加了内存。
现在,要进行查询,您可以将 CachingIterator 或 SplFileObject 包装到 FilterIterator 中,这将在迭代 csv 数据时限制输出
class BannedEntriesFilter extends FilterIterator
{
private $bannedEntries = array();
public function setBannedEntries(array $bannedEntries)
{
$this->bannedEntries = $bannedEntries;
}
public function accept()
{
foreach ($this->current() as $key => $val) {
return !$this->isBannedEntryInColumn($val, $key);
}
}
public function $isBannedEntryInColumn($entry, $column)
{
return isset($this->bannedEntries[$column])
&& in_array($this->bannedEntries[$column], $entry);
}
}
FilterIterator 将忽略内部 Iterator 中不满足 FilterIterator 的 accept 方法中的测试的所有条目。上面,我们检查 csv 文件中的当前行与一组禁止条目,如果匹配,则数据不包含在迭代中。你像这样使用它:
$filteredCachedFile = new BannedEntriesFilter(
new ArrayIterator($cachedFile->getCache())
)
由于缓存的结果始终是一个数组,因此我们需要将该数组包装到一个 ArrayIterator 中,然后才能将其包装到我们的 FilterIterator 中。请注意,要使用缓存,您还需要至少迭代一次 CachingIterator。我们只是假设你已经在上面做了。下一步是配置禁止条目
$filteredCachedFile->setBannedEntries(
array(
// banned entries for column 0
array('foo', 'bar'),
// banned entries for column 1
array( …
)
);
我想这很简单。您有一个多维数组,其中包含禁止条目的 CSV 数据中的每一列都有一个条目。然后,您只需遍历实例,它只会为您提供没有被禁止条目的行
foreach ($filteredCachedFile as $row) {
// do something with filtered rows
}
或者,如果您只想将结果放入数组中:
$results = iterator_to_array($filteredCachedFile);
您可以堆叠多个 FilterIterators 以进一步限制结果。如果您不想为每个过滤编写一个类,请查看 CallbackFilterIterator,它允许在运行时传递接受逻辑:
$filteredCachedFile = new CallbackFilterIterator(
new ArrayIterator($cachedFile->getCache()),
function(array $row) {
static $bannedEntries = array(
array('foo', 'bar'),
…
);
foreach ($row as $key => $val) {
// logic from above returning boolean if match is found
}
}
);