Самый эффективный способ объединения и перестановки файлов - PullRequest
2 голосов
/ 24 марта 2010

Я читаю из нескольких файлов, каждый файл разделен на 2 части, сначала раздел заголовка из нескольких тысяч строк, а затем тело из нескольких тысяч. Моя проблема заключается в том, что мне нужно объединить эти файлы в один файл, где все заголовки находятся сверху, а за ними следует тело.

В настоящее время я использую два цикла: один для извлечения всех заголовков и записи их, а второй для записи тела каждого файла (я также включаю переменную tmp_count, чтобы ограничить число строк для загрузки в памяти перед сохранением в файл).

Это довольно медленно - около 6 минут для файла 13 ГБ. Может кто-нибудь сказать мне, как оптимизировать это или есть более быстрый способ сделать это в Python?

Спасибо!

Вот мой код:

def cat_files_sam(final_file_name,work_directory_master,file_count):

    final_file = open(final_file_name,"w")

    if len(file_count) > 1:
        file_count=sort_output_files(file_count)

    # only for @ headers    
    for bowtie_file in file_count:
        #print bowtie_file
        tmp_list = []

        tmp_count = 0
        for line in open(os.path.join(work_directory_master,bowtie_file)):
            if line.startswith("@"):

            if tmp_count == 1000000:
                final_file.writelines(tmp_list)
                tmp_list = []
                tmp_count = 0

            tmp_list.append(line)
            tmp_count += 1

        else:
            final_file.writelines(tmp_list)
            break

    for bowtie_file in file_count:
        #print bowtie_file
        tmp_list = []

        tmp_count = 0
        for line in open(os.path.join(work_directory_master,bowtie_file)):
            if line.startswith("@"):
            continue
        if tmp_count == 1000000:
            final_file.writelines(tmp_list)
            tmp_list = []
            tmp_count = 0

        tmp_list.append(line)
        tmp_count += 1
        final_file.writelines(tmp_list)

    final_file.close()

Ответы [ 3 ]

2 голосов
/ 24 марта 2010

Вы можете сэкономить время, которое занимает 2-й раз, чтобы пропустить заголовки, при условии, что у вас есть достаточное количество свободного дискового пространства: наряду с окончательным файлом также откройте (для 'w +') временный файл temp_file и сделайте:

import shutil

hdr_list = []
bod_list = []
dispatch = {True: (hdr_list, final_file), 
            False: (bod_list, temp_file)}

for bowtie_file in file_count:
    with open(os.path.join(work_directory_master,bowtie_file)) as f:
        for line in f:
            L, fou = dispatch[line[0]=='@']
            L.append(f)
            if len(L) == 1000000:
                fou.writelines(L)
                del L[:]

# write final parts, if any
for L, fou in dispatch.items():
    if L: fou.writelines(L)

temp_file.seek(0)
shutil.copyfileobj(temp_file, final_file)

Это должно повысить производительность вашей программы. Точная настройка, которая теперь жестко запрограммирована 1000000, или даже полное избавление от списков и запись каждой строки непосредственно в соответствующий файл (окончательный или временный), являются другими вариантами, которые вы должны сравнить (но если у вас есть неограниченное количество память, тогда я ожидаю, что они не будут иметь большого значения - однако, интуиция о производительности часто вводит в заблуждение, поэтому лучше попытаться измерить! -).

2 голосов
/ 24 марта 2010

Как вы думаете, с какой скоростью будет перемещаться 13 Гб данных? Эта проблема связана с вводом / выводом, а не с Python. Чтобы сделать это быстрее, делайте меньше операций ввода-вывода. Это означает, что вы либо (а) застряли на вашей скорости, либо (б) должны переоборудовать более поздние элементы вашей цепочки инструментов для обработки файлов на месте, чем требовать один гигантский файл 13 Гб.

0 голосов
/ 24 марта 2010

В коде, который вы намеревались написать (есть не тот код, который представлен), есть два грубых недостатка:

  1. Вы строите огромные списки строк заголовка в первом главном блоке for, а не просто записываете их.
  2. Вы пропускаете заголовки файлов снова во втором главном for блоке построчно, когда вы уже определили, где заканчиваются заголовки (1). См. file.seek и file.tell
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...