代码之家  ›  专栏  ›  技术社区  ›  martin

在python中逐行复制文件的更有效方法?

  •  0
  • martin  · 技术社区  · 3 年前

    我有一个10GB的文件,上面有这样的图案:

    Header,
    header2,
    header3,4
    content
    aaa, HO222222222222, AD, CE 
    bbb, HO222222222222, AS, AE 
    ccc, HO222222222222, AD, CE 
    ddd, HO222222222222, BD, CE 
    eee, HO222222222222, AD, CE 
    fff, HO222222222222, BD, CE 
    ggg, HO222222222222, AD, AE 
    hhh, HO222222222222, AD, CE 
    aaa, HO333333333333, AG, CE 
    bbb, HO333333333333, AT, AE 
    ccc, HO333333333333, AD, CT 
    ddd, HO333333333333, BD, CE 
    eee, HO333333333333, AD, CE 
    fff, HO333333333333, BD, CE 
    ggg, HO333333333333, AU, AE 
    hhh, HO333333333333, AD, CE 
    ....
    

    假设在第二列中我有一个ID。在整个文件中,我有4000人,每个人都有50k条记录。

    我不能用我准备好的脚本来分析那个大文件(熊猫中的10GB脚本,我的内存太低。我知道我应该重构它,我正在处理它),所以我需要将该文件分成4个部分。但我不能在文件之间分割ID。我的意思是我不能把一个人的一部分放在单独的文件里。

    所以我写剧本。它根据ID将文件分为4个部分。

    下面是代码:

    file1 = open('file.txt', 'r')
    count = 0
    list_of_ids= set()
    while True:
        if len(list_of_ids) < 1050:
            a = "out1.csv"
        elif (len(list_of_ids)) >= 1049 and (len(list_of_ids)) < 2100:
            a = "out2.csv"
        elif (len(list_of_ids)) >= 2099 and (len(list_of_ids)) < 3200:
            a = "out3.csv"
        else:
            a = "out4.csv"
            
        line = file1.readline()
     
        if not line:
            break
        
        try:
            
            list_of_ids.add(line.split(',')[1])
            out = open(a, "a")
            out.write(line)
            
        except IndexError as e:
            print(e)
        count += 1
        
     
        
    out.close()
    

    但是速度太慢了,我需要加快速度。 有很多if,每次我打开文件时,我都不知道如何获得更好的性能。 也许有人有一些建议?

    1 回复  |  直到 3 年前
        1
  •  2
  •   Grismar    3 年前

    我想你更想要这样的东西:

    # this number is arbitrary, of course
    ids_per_file = 1000
    # use with, so the file always closes when you're done, or something happens
    with open('20220317_EuroG_MD_v3_XT_POL_FinalReport.txt', 'r') as f:
        # an easier way to loop over all the lines:
        n = 0
        ids = set()
        try:
            for line in f:
                try:
                    ids.add(line.split(',')[1])
                except IndexError:
                    # you don't want to break, you just want to ignore the line and continue
                    continue
                # when the number ids reaches the limit (or at the start), start a new file
                if not n or len(ids) > ids_per_file:
                    # close the previous one, unless it's the first
                    if n > 0:
                        out_f.close()
                    # on to the next
                    n += 1
                    out_f = open(f'out{n}.csv', 'w')
                    # reset ids
                    ids = {line.split(',')[1]}
                # write the line, if you get here, it's a record
                out_f.write(line)
        finally:
            # close the last file
            out_f.close()
    

    编辑:实际上有一个bug,会将第一个新的标识符写入前一个文件,认为这样更好。