如何以高效内存的方式在python中拆分和解析一个大文本文件?

时间:2013-03-24 19:19:53

标签: python parsing file-io ascii

我有一个很大的文本文件要解析。 主要模式如下:

step 1

[n1 lines of headers]

  3  3  2
 0.25    0.43   12.62    1.22    8.97
12.89   89.72   34.87   55.45   17.62
 4.25   16.78   98.01    1.16   32.26
 0.90    0.78   11.87
step 2

[n2 != n1 lines of headers]

  3  3  2
 0.25    0.43   12.62    1.22    8.97
12.89   89.72   34.87   55.45   17.62
 4.25   16.78   98.01    1.16   32.26
 0.90    0.78   11.87
step 3

[(n3 != n1) and (n3 !=n2) lines of headers]

  3  3  2
 0.25    0.43   12.62    1.22    8.97
12.89   89.72   34.87   55.45   17.62
 4.25   16.78   98.01    1.16   32.26
 0.90    0.78   11.87
换句话说,

  

分隔符:步骤#

     

已知长度的标题(行号,而不是字节)

     

数据三维形状:nz,ny,nx

     

数据:fortran格式化,原始数据集中的~10个浮点数/行

我只是想提取数据,将它们转换为浮点数,将它放在一个numpy数组中,然后将ndarray.reshape转换为给定的形状。

我已经做了一些编程......主要的想法是

  1. 首先获取每个分隔符的偏移量(“步骤X”)
  2. 跳过nX(n1,n2 ...)行+ 1以到达数据
  3. 从那里读取字节一直到下一个分隔符。
  4. 我想首先避免使用正则表达式,因为这会使事情变得很慢。完成第一步已经需要3-4分钟(浏览文件以获得每个部分的偏移量)。

    问题在于我基本上使用file.tell()方法来获取分隔符位置:

    [file.tell() - len(sep) for line in file if sep in line]
    

    问题是双重的:

    1. 对于较小的文件,file.tell()给出正确的分隔符位置,对于较长的文件,它不会。我怀疑file.tell()不应该在循环中使用,既不使用显式file.readline()也不使用隐式for line in file(我试过两者)。我不知道,但结果是:对于大文件,[file.tell() for line in file if sep in line] 系统地在分隔符后面提供行的位置。
    2. len(sep)没有给出正确的偏移校正以返回“分隔符”行的开头。 sep是一个字符串(字节),包含文件的第一行(第一个分隔符)。
    3. 有谁知道我应该如何解析它?

      注意:我首先找到偏移量,因为我希望能够浏览文件内部:我可能只想要第10个数据集或第500个数据集......

      1-查找偏移量

      sep = "step "
      with open("myfile") as f_in:
          offsets = [fin.tell() for line in fin if sep in line]
      

      正如我所说,这是在一个简单的例子中,但不是在大文件上。

      新测试:

      sep = "step "
      offsets = []
      with open("myfile") as f_in:
          for line in f_in:
              if sep in line:
                  print line
                  offsets.append(f_in.tell())
      

      打印的行对应于分隔符,毫无疑问。但是使用f_in.tell()获得的偏移量与下一行不对应。我想文件是在内存中缓冲的,当我尝试在隐式循环中使用f_in.tell()时,我没有获得当前位置而是缓冲区的结尾。这只是一个疯狂的猜测。

1 个答案:

答案 0 :(得分:0)

我得到了答案:for - 文件上的循环和tell()相处得不好。就像混合for i in filefile.readline()会引发错误一样。

因此,file.tell()仅使用file.readline()file.read()

永远不要使用

for line in file:
    [do stuff]
    offset = file.tell()

这真是一种耻辱,但就是这样。