2010-10-29 53 views
3

我有一个csv文件,记录被排序在第一个字段。我设法生成一个函数,通过该文件进行二分搜索,使用fseek通过文件进行随机访问。php文件随机访问和文件保存对象

但是,这仍然是一个非常缓慢的过程,因为当我寻找某个文件位置时,实际上我需要向左看,寻找\ n字符,因此我可以确保我正在读整行(整个行被读取,我可以检查上面提到的第一个字段值)。

这里是返回一个包含字符在位置的直线x功能:

 

function fgetLineContaining($fh, $x) { 
     if($x 125145411) // 12514511 is the last pos in my file 
      return ""; 
     // now go as much left as possible, until newline is found 
     // or beginning of the file 
     while($x > 0 && $c != "\n" && $c != "\r") { 
      fseek($fh, $x); 
      $x--; // go left in the file 
      $c = fgetc($fh); 
     } 
     $x+=2; // skip newline char 
     fseek($fh, $x); 
     return fgets($fh, 1024); // return the line from the beginning until \n 
    } 
 

虽然这是按预期工作,我不得不悲哀的是我的CSV文件〜1.5Mil行,这些左派的追求正在减缓。

有没有更好的方法来寻找一个文件中的位置x

另外,如果一个类的对象可以保存到一个文件而不需要序列化,那么它会好得多,从而能够逐个对象地读取文件。 PHP支持吗?

感谢

+0

另外,还有另外一个想法出现在我脑海里 - 如何对文件进行采样 - 从文件中每1000个条目取一个条目并将其存储到数组中。这将产生1500个元素数组,我可以进行二分法搜索,在所需的线上得到粗略的近似值。然后我可以加载剩余的1000个元素并对它们进行二分搜索。这是否做同样的事情? – hummingBird 2010-10-29 21:18:05

+1

你在这个文件上执行什么样的搜索?文件是否经常更改?如果您要在同一个文件上执行多次搜索,将数据加载到SQLite数据库并搜索数据库可能会快很多。 – kijin 2010-10-29 21:31:30

+1

如果你知道一条平均线的长度,你可以稍微返回一点,做'fgets()'来将指针与前一行的末尾或者之前的几行对齐。二进制搜索的目的应该足够好。 – kijin 2010-10-29 21:32:45

回答

1

我觉得你真的应该考虑使用SQLite或MySQL再次(像别人一样的意见建议)。有关预先计算索引的大部分建议已在这些SQL引擎中“正确”实施。

你说SQL的速度不够好。你有正确索引的字段吗?你如何查询数据?你在哪里使用批量查询,在哪里使用准备好的语句? SQL进程是否有足够的内存将其索引存储在RAM中?

在当前的算法下,您可以尝试加速的一件事是将(〜100MB?)文件加载到RAM磁盘上。无论您选择做什么,无论是CVS还是SQLite,这都有助于加快速度,特别是如果硬盘寻找时间成为瓶颈。

你甚至可能读整个文件到PHP数组(假设你的计算机有足够的RAM)。这将允许您通过索引($big_array[$offset])查找进行搜索。

还有一件事要记住,PHP在快速执行低级别事情时并不是非常快速。您可能想考虑从PHP转向C或C++。

+0

那么,这个问题的sql部分位于赏金问题下,在此链接(http://stackoverflow.com/questions/4007671/effective-ip-location-query)。我没有mysql优化的经验,并且不得不说我不知道​​所有问题的答案。 – hummingBird 2010-10-29 23:39:30

+0

也许更小的数据库会做这项工作? – hummingBird 2010-10-29 23:41:32

+0

我设法得到3-4次加速使用2个更多的aditional文件与排序的二进制搜索:) – hummingBird 2010-11-01 15:10:19