在文件中输入列表项

问题描述 投票:0回答:2

下午好,我有一个IP和MAC的多个列表,任意长度的列表

A = [['10.0.0.1','00:4C:3S:**:**:**', 0], ['10.0.0.2', '00:5C:4S:**:**:**', 0], [....], [....]]

我想检查这个MAC是否在oui文件中:

E043DB   (base 16)   Shenzhen
2405f5   (base 16)   Integrated
3CD92B   (base 16) Hewlett Packard
...

如果列表中的MAC位于文件中,请将制造商的名称写为3个列表项。我试图这样做,结果只检查第一个元素,剩下的没有检查,我怎么能这样做请告诉我?

f = open('oui.txt', 'r')
for values in A:
    for line in f.readlines():
        if values[1][0:8].replace(':','') in line:
            values[2]=(line.split('(base 16)')[1].strip())
f.close()
print (A)

得到答案:

A = [['10.0.0.1','00:4C:3S:**:**:**', 'Firm Name'], ['10.0.0.2', '00:5C:4S:**:**:**', 0], [....], [....]]
python python-3.x list readfile
2个回答
0
投票

问题

考虑代码的“形状”:

f = open('a file')
for values in [ 'some list' ]:
    for line in f.readlines():

你的两个循环是这样做的:

Start with first value in list
Read all lines remaining in file object f
Move to next value in list
Read all lines remaining in file object f

除了你第一次告诉它“读取剩下的所有行”之外,它会这样做。

所以,除非你有办法将更多行放入f(这可能发生在像stdin这样的异步文件!),你将获得一个“好”的文件传递,然后每个后续传递文件对象将指向文件的结尾,所以你什么也得不到。

一个办法

处理文件时,您只想处理一次。与其他操作相比,文件I / O很昂贵。所以你可以选择(a)将整个文件读入内存,并做任何你想做的事情,因为它不再是文件了;或(b)只扫描一次。

如果您选择仅扫描一次,那么简单的解决方案就是将两个for循环反转。而不是这样做:

for item in list:
    for line in file:

改为:

for line in file:
    for item in list:

并且presto!您现在只阅读该文件一次。

其他考虑因素

如果我查看您的代码和示例,您似乎正在尝试在特定密钥上进行完全匹配。您减少列表中的MAC地址,以根据制造商ID进行检查。

这告诉我,您可能拥有比制造商更多的列表值(源MAC地址)。所以也许您应该考虑将磁贴的内容读入内存,而不是一次处理一行。

将文件存入内存后,请考虑构建正确的字典。您有一个密钥(MAC前缀)和一个值(制造商)。所以建立像:

for line in f:
    mac = line.split('(base 16)')[0].strip()
    mfg = line.split('(base 16)')[1].strip()
    mac_to_mfg[mac] = mfg

然后你可以通过源地址进行一次传递,并使用dict的O(1)查找来获得优势:

for src in A:
    prefix = src[1][:8].replace(':', '')
    if prefix in mac_to_mfg:
        # etc...

0
投票

问题是你得到了循环的顺序颠倒了。通常这不是一个大问题,但是当处理被消耗的对象(如IO文件对象)时,内容将在迭代后不再生成。

你需要首先迭代lines,然后在每个lines中迭代A来检查值:

with open('oui.txt', 'r') as f:
    for line in f.readlines():
        for values in A:
            if values[1][0:8].replace(':','') in line:
                values[2]=(line.split('(base 16)')[1].strip())

print (A)

请注意我改变了你的文件开放使用with context manager代替,一旦你的代码存在with块它将自动close()文件给你。建议手动opening文件,因为你可能会忘记close()后。

© www.soinside.com 2019 - 2024. All rights reserved.