在python中处理大型文本文件

时间:2019-03-15 16:51:56

标签: python dictionary large-files

我正在处理2个大文件。主文件有2个字段,分别是客户名称和第二个字段,分别是客户ID。我有第二个文件,它是第一个文件的子集,只有客户名称。 我希望找到子集文件中存在的名称的客户ID。

第一个文件有3000万行,第二个文件有500万行。

我正在尝试使用字典来做,但是要花很多时间。

您能建议我一种更好的方法吗?

这是我的代码段和文件中的几行内容。

主文件

约翰2343245

卡里姆(Karim)126754

Rob 6543289

维杰2247861

山姆2649860

....

子集第二个文件

山姆

Rob

约翰

def extract_info(sub_file,master_file):
    sub_fh = open(sub_file,'r',16777216)
    sub_inst_list = []
    for line in sub_fh:
        if line.startswith('#'):
            continue
        else:
            name = line.rstrip()
            sub_inst_list.append(name)
    sub_fh.close()


out_file = "results.rpt"
outf = open(out_file,'w')
bunchsize = 10000
bunch = []
master_fh = open(master_file,'r',16777216)
for line in master_fh:
    if line.startswith('#'):
        continue
    else:
        data = line.split()
        name = data[0]
        if str(data[1]) == "n/a":
            continue
        else:
            if name in sub_inst_list:
                id = str(data[1])
                line = "%-80s %-15s\n" % (name, id)
                bunch.append(line)
                if len(bunch) == bunchsize: 
                    outf.writelines(bunch)
                    bunch= []
                outf.writelines(bunch)
  master_fh.close()
  outf.close()

2 个答案:

答案 0 :(得分:1)

更好的方法是将主文件中的所有数据放入数据库中,然后根据第二个文件中的键查找值:

private List<Task> taskEventList = new List<Task>();
public async Task ProcessStart()
{
    string messageData = "{\"name\":\"DemoData\",\"no\":\"111\"}";
    RegistryManager registryManager;

    Parallel.ForEach(deviceList, async (device) =>
    {
        // get details for each device and use key to send message
        device = await registryManager.GetDeviceAsync(device.DeviceId);
        SendMessages(device.DeviceId, device.Key, messageData);
    });

    if (taskEventList.Count > 0)
    {
        await Task.WhenAll(taskEventList);
    }
}

private void SendMessages(string deviceId, string Key, string messageData)
{
    DeviceClient deviceClient = DeviceClient.Create(hostName, new DeviceAuthenticationWithRegistrySymmetricKey(deviceId, deviceKey), Microsoft.Azure.Devices.Client.TransportType.Mqtt);
    //created separate Task
    var taskEvents = Task.Run(() => ProcessMessages(deviceId, string messageData));
    taskEventList.Add(taskEvents);
}

private async Task ProcessMessages(string deviceId, string messageData)
{
    var startTime = DateTime.UtcNow;
    while (DateTime.UtcNow - startTime < TimeSpan.FromMinutes(15))
    {
        await deviceClient.SendEventAsync(messageData);
    }
}

答案 1 :(得分:0)

另一种可能的解决方案(可能比ForceBru的慢,但嘿,编写XD很有趣)是使用线程来大大减少时间:

from queue import Queue
from threading import Thread

q = Queue()
number_of_threads = 3


def get_customer_id():
    while True:
        customer_name = q.get()
        with open('Master.txt', 'r') as f:
            for line in f.readlines():
                if customer_name.strip() in line:
                    print(line.strip())
                    break
        q.task_done()


with open('Slave.txt', 'r') as f:
    for line in f.readlines():
        q.put(line)

for i in range(number_of_threads):
    new_thread = Thread(target=get_customer_id)
    new_thread.setDaemon(True)
    new_thread.start()


print('main thread waiting')
q.join()
print('done')

您可以增加线程数,例如说100-200,然后让它们弯曲!尽管您的最大迭代次数接近最差情况的125,000,000,000,000,但这将在计算上非常昂贵。但是,这相当夸张,因为break语句应该减少大量的迭代。而且,如果它运行在100个线程中,那么您可以在将数字从break中减少后将其除以100(假设您尚未达到CPU使用率最大化的情况,那么在这种情况下,多处理将更为出色)。尽管使用这种方法计算起来很简单。

这实际上与初始脚本所做的相同,但是通过划分和征服它可以将其运行很多倍!