如何在python中输入1000万行的大文件?

时间:2015-04-06 16:12:57

标签: python

我想在python中分析一个拥有1000万用户和密码的文件。文件采用文本格式。以下是一些数据:

0000    00000000
0000    00001
0000    00001111
0000    000099
0000    00009999
0000    0000w
0000    5927499
0000    634252
0000    6911703
0000    701068

在python中,我使用以下代码来读取文件:

f=open('10-million-combos.txt','r')
a=[]
for line in f.readlines():
    a.append(line)

上面的代码需要几秒钟才能运行。保存在列表中的数据如下所示:

>>>a[0:2]
['0000\t00000000\n', '0000\t00001\n']

提取我使用过的用户和密码:

b=[]
for i in a:
    b.append(i.split('\t'))

问题是,上面的代码在很长一段时间后遇到内存错误,我无法分离用户和密码。

您对解决方案有什么建议吗?

6 个答案:

答案 0 :(得分:6)

问题是你正在将每一行读入Python列表。文件有多大?这就是你投入记忆的程度。

在同一步骤中进行阅读和分析,以便Python可以进行垃圾收集。

当您进入分析部分时,您可能需要查看Pandas,这是一个用于数据分析的库。

建议您附加到列表的其他答案将会遇到与内存使用相同的问题。诀窍是不要构建列表,逐步进行分析,这样就不需要在内存中存储10M行。

如果您按照评论中的说明递增总计,并且绝对必须将其存储在内存中,则可以将值存储为字典中的键并递增计数。

这仍会导致内存使用,因此如果它仍然崩溃,您的选项将是:

  • 每次迭代都持续到磁盘(写另一个文件)。然后你可以读取每个文件并获取总数,并找出哪一个具有最高总数和一个变量。这将是缓慢的,但会交换磁盘使用的内存使用量。

  • 使用修改后的二叉树来防止存储任何位两次,并添加一个可以递增到节点的“times”变量:

    AB ABC ABC A {时间:0} - > B {次:1} - > C {次:2}

答案 1 :(得分:2)

只需迭代每一行,然后根据制表符进行拆分,然后将返回的列表追加到已声明的列表l

l = []
with open('10-million-combos.txt','r') as f:
    for line in f:
        l.append(line.strip().split('\t'))

答案 2 :(得分:2)

同时读取和分割会减少所需的内存:

b = []
with open('10-million-combos.txt','r') as inp:
    for line in inp:
        b.append(line.strip().split('\t',1))

答案 3 :(得分:1)

如果文件是tsv,它似乎是,你总是可以使用pythons csv模块。

import csv


with open('10-million-combos.txt','r') as f:
    reader = csv.reader(f, delimiter="\t")
    for line in reader:
        user_name = line[0]
        password  = line[1]
        ....

这应该允许您迭代地解析文件并执行您需要做的事情而不将所有行保存到大列表中。

答案 4 :(得分:1)

除了其他答案之外,你还可以考虑使用只在你真正需要的时候加载数据的生成器(想想懒惰的评估):

def read_password_file(filename):
    with open(filename) as f:
        for line in f:
            yield line.strip()  # yield from f should be better starting in 3.3

def split_password(lines):
    for line in lines:
        yield line.split('\t')

a = read_password_file('10-million-combos.txt')
b = split_password(a)

答案 5 :(得分:1)

坦率地说,我很惊讶你没有足够的内存来将185MB文件读入内存,即使你有效地创建了它的两个副本。现在大多数现代系统都有大量的内存供你使用。

这里只创建了一个元组列表,它将比代码中的列表列表小。

假设成功,可以在数据集中找到最常见的用户ID和密码,

from collections import Counter  # dictionary subclass

records = []
with open('10-million-combos.txt', 'rU') as inf:
    for line in (line.strip() for line in inf):
        records.append(tuple(line.split('\t', 1)))

# display some of the test data read
print('Data:')
for rec in records[0:10]:
    print(rec)
print('')

# find most common user id
counter = Counter((rec[0] for rec in records))
print('most common user id: {}'.format(counter.most_common(1)[0][0]))

# find most common password
counter = Counter((rec[1] for rec in records))
print('most common password: {}'.format(counter.most_common(1)[0][0]))

输出:

Data:
('0000', '00000000')
('0002', '00001')
('0002', '00001111')
('0003', '000099')
('0004', '00009999')
('0006', '000099')
('0006', '5927499')
('0006', '634252')
('0008', '6911703')
('0009', '701068')

most common user id: 0006
most common password: 000099

注意:我更改了您问题中的示例数据,因此会有一些重复的user_id和密码。