Python:分块读取大文件

4

你好,我有一个相当大的文件想要使用Python处理,但我不知道该怎么做。

我的文件格式如下:

0 xxx xxxx xxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
1 xxx xxxx xxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

因此,我想读取从0到1之间的块,对其进行处理,然后转移到1到2之间的块。

到目前为止,我已经尝试使用正则表达式来匹配数字并继续迭代,但我相信肯定有更好的方法来处理这个问题。任何建议/信息将不胜感激。


正则表达式技术出了什么问题吗?这是相当常见的。请发布代码。 - S.Lott
这是来自neopythonic的一个例子 http://neopythonic.blogspot.in/2008/10/sorting-million-32-bit-integers-in-2mb.html - Pramod
6个回答

3
如果它们都在同一行内,也就是在“1.”和“2.”之间没有换行符,则可以按以下方式遍历文件的每一行:
for line in open("myfile.txt"):
    #do stuff

每次迭代时,该行将被处理并覆盖,这意味着您可以轻松处理大文件大小。如果它们不在同一行:

for line in open("myfile.txt"):
    if #regex to match start of new string
       parsed_line = line
    else:
       parsed_line += line

以及你的代码中的其余部分。


我给了一个+1。但是这里有一些棘手的情况,因为只有在读取下一个数据行(以“N”开头的行)时才知道结束条件。在这种情况下,需要使用读取的最后一行作为下一个项目的第一个数据。(实际上,我认为只需将parsed_line实际使用的调用站点存根化即可澄清关于排序的问题;这取决于几个边缘情况)。 - user166390
@pst 很好的发现。你指出了一些边缘情况。 - wheaties

2
为什么不使用file.read(1)逐个字符读取文件?然后,您可以在每次迭代中检查是否到达字符1。然后,您需要确保存储字符串的速度快。

1

如果“N”只能在一行开头出现,那么为什么不使用“简单”的解决方案呢?(听起来好像已经这样做了,我正在尝试加强/支持它;-)

也就是说,每次只读取一行,并构建表示当前N对象的数据。在加载N=0和N=1之后,一起处理它们,然后移动到下一对(N=2,N=3)。唯一稍微棘手的事情就是确保不要丢弃读取的行。(确定结束条件的读取行--例如“N”--还包含下一个N的数据)。

除非需要寻找(或IO缓存被禁用或每个项目有荒谬的数据量),否则没有理由不使用readline AFAIK。

愉快的编码。


这里是一些即兴编写的代码,很可能包含多个错误。无论如何,它展示了使用最小化副作用方法的一般思路。

# given an input and previous item data, return either
# [item_number, data, next_overflow] if another item is read
# or None if there are no more items
def read_item (inp, overflow):
  data = overflow or ""

  # this can be replaced with any method to "read the header"
  # the regex is just "the easiest". the contract is just:
  # given "N ....", return N. given anything else, return None
  def get_num(d):
    m = re.match(r"(\d+) ", d)
    return int(m.groups(1)) if m else None

  for line in inp:
    if data and get_num(line) ne None:
      # already in an item (have data); current line "overflows".
      # item number is still at start of current data
      return [get_num(data), data, line]

    # not in item, or new item not found yet
    data += line

  # and end of input, with data. only returns above
  # if a "new" item was encountered; this covers case of
  # no more items (or no items at all)
  if data:
    return [get_num(data), data, None]
  else
    return None

使用方法可能类似于以下示例,其中f表示一个打开的文件:

# check for error conditions (e.g. None returned)
# note feed-through of "overflow"
num1, data1, overflow = read_item(f, None)
num2, data2, overflow = read_item(f, overflow)

0
如果格式固定,为什么不使用readline()一次读取3行呢?

虽然我发的帖子可能暗示了这一点,但它并不是固定的。数字之间可能有任意数量的行。 - Teeps
所以你想读取以数字开头的行?xxxxxx中的文本没有可能包含一个数字,它会换到新的一行吗?这些行是分隔的吗? - tMC
xxx 可以是数字,但是每个记录的第一个数字是连续的,从 1 到 n。记录由 \n 分隔,在下一个连续数字之前结束。 - Teeps
整个文件能否放入内存? - tMC

0
如果文件很小,你可以将整个文件读入并使用split()函数拆分数字(可能需要使用strip()函数去除空格和换行符),然后折叠列表以处理列表中的每个字符串。你可能需要检查正在处理的结果字符串是否最初为空,以防两个数字相邻。

如果您只想在行首查找数字,则可能不应该剥离(实际上我不确定剥离对您是否有用),而是通过正则表达式拆分换行符数字组合进行拆分:[link]http://docs.python.org/library/re.html#re.split - aterimperator
文件非常大(约1.2GB)。 - Teeps
如果你正在寻找按顺序排列在行首的数字集合...那么你应该编写自己的分割函数,它只需迭代字符串并在适当的时间进行分割...由于这是一个大文件,我认为phimuemue是正确的:你应该逐个字符地读取它,并且你的处理部分应该是“这是下一个定界符的换行符序列吗?” - aterimperator

0
如果文件的内容可以加载到内存中,并且这是您回答的内容,那么以下代码(需要定义文件名)可能是一个解决方案。
import re

regx = re.compile('^((\d+).*?)(?=^\d|\Z)',re.DOTALL|re.MULTILINE)

with open(filename) as f:
    text = f.read()

def treat(inp,regx=regx):
    m1  = regx.search(inp)
    numb,chunk = m1.group(2,1)
    li = [chunk]
    for mat in regx.finditer(inp,m1.end()):
        n,ch = mat.group(2,1)
        if int(n) == int(numb) + 1:
            yield ''.join(li)
            numb = n
            li = []
        li.append(ch)
        chunk = ch
    yield ''.join(li)

for y in treat(text):
    print repr(y)

这段代码可以在包含以下内容的文件上运行:

1 mountain
orange 2
apple
produce
2 gas
solemn
enlightment
protectorate
3 grimace
song
4 snow
wheat
51 guludururu
kelemekinonoto
52asabi dabada
5 yellow
6 pink 
music
air
7 guitar
blank 8
8 Canada
9 Rimini

产生:

'1 mountain\norange 2\napple\nproduce\n'
'2 gas\nsolemn\nenlightment\nprotectorate\n'
'3 grimace\nsong\n'
'4 snow\nwheat\n51 guludururu\nkelemekinonoto\n52asabi dabada\n'
'5 yellow\n'
'6 pink \nmusic\nair\n'
'7 guitar\nblank 8\n'
'8 Canada\n'
'9 Rimini'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接