Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 对未知行长的大型文件进行二进制搜索_Python_Database_Io_Binary Search_Large Files - Fatal编程技术网

Python 对未知行长的大型文件进行二进制搜索

Python 对未知行长的大型文件进行二进制搜索,python,database,io,binary-search,large-files,Python,Database,Io,Binary Search,Large Files,我正在处理巨大的数据CSV文件。每个文件包含数以百万计的记录,每个记录都有一个键。这些记录按它们的键排序。在搜索特定数据时,我不想浏览整个文件。 我已经看到了这个解决方案: 但它建议您在文件上使用相同长度的行-这在我的案例中不受支持 我曾想过在每行中添加一个填充,然后保持固定的行长,但我想知道是否有更好的方法 我使用的是python,您不必拥有固定宽度的记录,因为您不必进行面向记录的搜索。相反,您可以只执行面向字节的搜索,并确保在执行搜索时重新对齐键。下面是一个(可能有问题)示例,说明如何将链接

我正在处理巨大的数据CSV文件。每个文件包含数以百万计的记录,每个记录都有一个键。这些记录按它们的键排序。在搜索特定数据时,我不想浏览整个文件。 我已经看到了这个解决方案:

但它建议您在文件上使用相同长度的行-这在我的案例中不受支持

我曾想过在每行中添加一个填充,然后保持固定的行长,但我想知道是否有更好的方法


我使用的是python,您不必拥有固定宽度的记录,因为您不必进行面向记录的搜索。相反,您可以只执行面向字节的搜索,并确保在执行搜索时重新对齐键。下面是一个(可能有问题)示例,说明如何将链接到的解决方案从面向记录修改为面向字节:

bytes = 24935502 # number of entries
for i, search in enumerate(list): # list contains the list of search keys
  left, right = 0, bytes - 1 
  key = None
  while key != search and left <= right:
    mid = (left + right) / 2
    fin.seek(mid)
    # now realign to a record
    if mid:
        fin.readline()
    key, value = map(int, fin.readline().split())
    if search > key:
      left = mid + 1
    else:
      right = mid - 1
  if key != search:
    value = None # for when search key is not found
  search.result = value # store the result of the search
bytes=24935502#条目数
对于i,在枚举(列表)中搜索:#列表包含搜索键列表
左,右=0,字节-1
键=无
而钥匙搜索和左键:
左=中+1
其他:
右=中-1
如果是钥匙!=搜索:
值=无#用于未找到搜索键时
search.result=value#存储搜索结果

参考问题的答案是,二进制搜索只适用于固定长度的记录,这是错误的。而且您根本不需要进行搜索,因为您有多个项目要查找。只需一行一行地浏览整个文件,为每一行构建一个包含
key:offset
的字典,然后使用每个键对应的偏移量上的
os.lseek
跳转到感兴趣的记录


当然,如果您甚至不想读取整个文件一次,那么必须进行二进制搜索。但是,如果建立索引可以在多次查找中摊销,如果您每天只进行一次查找,则可能会保存索引,则无需进行搜索。

要解决此问题,您也可以使用二进制搜索,但需要对其进行一点更改:

  • 获取文件大小
  • 使用File.Seek搜索到中间大小
  • 并搜索第一个下线字符。然后你找到一条新的线路
  • 检查此行的键,如果不是您想要的,则更新大小并转到2
  • 下面是一个示例代码:

    fp = open('your file')
    fp.seek(0, 2)
    begin = 0
    end = fp.tell()
    
    while (begin < end):
        fp.seek((end + begin) / 2, 0)
        fp.readline()
        line_key = get_key(fp.readline())
        if (key == line_key):
            pass # find what you want
        elif (key > line_key):
            begin = fp.tell()
        else:
            end = fp.tell()
    
    fp=open('您的文件')
    fp.seek(0,2)
    开始=0
    end=fp.tell()
    while(开始<结束):
    fp.seek((结束+开始)/2,0)
    fp.readline()
    line\u key=get\u key(fp.readline())
    如果(键==行\键):
    传球#找到你想要的
    elif(键>行\键):
    begin=fp.tell()
    其他:
    end=fp.tell()
    

    也许代码有bug。验证你自己。如果你真的想用最快的方法,请检查性能。

    @Mat-现在没有选择。我有一个非常有限的最后期限,没有足够的时间从这些数据创建数据库。在字节级别进行二进制搜索,然后在搜索之后找到最近的换行符。sqlite似乎有一个自动csv导入选项。没有人的二进制搜索第一次能正常工作。到现在为止,您可能已经有了一个数据库解决方案并正在运行。你有多少不同的大文件?记录的典型数量是多少?以GB为单位的典型文件大小是多少?键是数字还是字符串?似乎永远找不到第一行。