如何索引 csv 文件:
要索引 csv 文件,您需要将其作为二进制文件而不是文本文件读取。使用 128、256 或 512 块大小。要构建索引,您扫描文件以查找每条记录的开头,然后创建一个索引文件,如下所示:
key-value-1, 0, 0
........
........
key-value-n, block, offset
key-value 是您索引的键的值。可以是复合键。 block 是记录开始的区块编号(请注意,您的记录可以跨越多个区块),offset 是介于0 和 block-size-1 是该块的偏移量。要检索您的记录,您可以在索引文件中查找键(可能使用binary search),然后使用块偏移来访问您的记录directly。
如果需要搜索不同的条件,也可以同时创建多个索引文件。
如果您将CR-LF 作为行尾标记,请注意CR 可以位于块的确切末尾,而LF 将位于下一个块的开头。您需要注意一些像这样的特殊情况。创建此索引文件(或多个文件)后,您可以按键对其进行排序,一切顺利。
或者,如果您的软件允许快速内存块移动(如 C++ memmove),您可以将 insertion sort 与二分搜索结合使用。这样,在您完成构建索引后,它们就已经排序。如果索引条目是从使用慢速输入设备(例如,keyboard)捕获的文件中添加的,这将特别有效。如果您要管理大量记录,请考虑为您的索引使用 B-Tree 结构。
此架构允许您的 csv 数据库 接受记录添加、删除和更新。 添加在文件末尾。要删除记录,只需将记录的第一个字符更改为 0x0 这样的唯一字符,当然还可以从索引文件中删除条目。 更新可以通过在文件末尾删除然后添加更新的记录来实现。
这将在您的数据库上创建一些garbage collection 的需求,但大多数DBMS(如果不是全部)都这样做。定期重建索引并清除已删除的记录。
注意:对于代码实现look at this answer.,索引 6867839 行的 9 Gb csv 文件大约需要 6 分钟。 Joblib 在磁盘上存储索引非常慢。索引文件为 134 Mb。
让我们使用一个玩具 csv 示例。我们将按记录号索引文件。为了示例的目的,我们将记录号存储在索引的关键部分,尽管这显然是不必要的。
strings,numbers,colors
string1,1,blue
string2,2,red
string3,3,green
string4,4,yellow
索引文件将存储在列表idx:
idx
[[0, 0, 0], [1, 0, 24], [2, 0, 40], [3, 0, 55], [4, 0, 72], [5, 0, -1]]
注意最后一个索引元素处的 -1 表示在顺序访问的情况下索引文件的结尾。您可以使用这样的代码按记录编号访问 csv 文件的任何单独行:
def get_rec(n=1,binary=False):
n=1 if n<0 else n+1
s=b'' if binary else ''
if len(idx)==0:return ''
if idx[n-1][2]==-1:return ''
f.seek(idx[n-1][1]*BLKSIZE+idx[n-1][2])
buff=f.read(BLKSIZE)
x=buff.find(b'\r')
while x==-1:
s=s+buff if binary else s+buff.decode()
buff=f.read(BLKSIZE)
x=buff.find(b'\r')
return s+buff[:x]+b'\r\n' if binary else s+buff[:x].decode()