Обрабатывать два файла одновременно в Python - PullRequest
4 голосов
/ 13 ноября 2009

У меня есть информация о 12340 автомобилях. Эта информация хранится последовательно в двух разных файлах:

  1. car_names.txt, который содержит одну строку для названия каждого автомобиля
  2. car_description.txt, который содержит описания каждого автомобиля. Итак, 40 строк для каждой, где 6-я строка читается как @ CAR_NAME

Я хотел бы сделать в python: добавить для каждого автомобиля в файл car_description.txt название каждого автомобиля (которое происходит из другого файла) в 7-й строке (она пуста) сразу после @ CAR_NAME

Я думал о:

1) прочитать 1-й файл и сохранить названия автомобилей в матрице / списке 2) начать читать 2-й файл и каждый раз, когда он находит строку @CAR_NAME, просто напишите имя на следующей строке

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

Спасибо

Ответы [ 6 ]

9 голосов
/ 13 ноября 2009

Сначала создайте генератор, который извлекает название автомобиля из последовательности. Вы можете сдать каждую 7-ю строку; Я сделал мой выход любой строки, следующей за строкой, которая начинается с @CAR_NAME:

def car_names(seq):
    yieldnext=False
    for line in seq:
        if yieldnext: yield line
        yieldnext = line.startswith('@CAR_NAME')

Теперь вы можете использовать itertools.izip для параллельного прохождения обеих последовательностей:

from itertools import izip
with open(r'c:\temp\cars.txt') as f1:
    with open(r'c:\temp\car_names.txt') as f2:
        for (c1, c2) in izip(f1, car_names(f2)):
            print c1, c2
8 голосов
/ 13 ноября 2009

Я не уверен, что я полностью понимаю, что вы пытаетесь сделать, что-то вроде этого?

f1 = open ('car_names.txt')
f2 = open ('car_descriptions.txt')
for car_name in f1.readlines ():
        for i in range (6):   # echo the first 6 lines
                print f2.readline ()
        assert f2.readline() == '@CAR_NAME'  # skip the 7th, but assert that it is @CAR_NAME
        print car_name    # print the real car name
        for i in range (33):  # print the remaining 33 of the original 40
               print f2.readline ()
4 голосов
/ 13 ноября 2009

Чтение car_names.txt сэкономит вам изрядное количество памяти (действительно очень маленькое по сегодняшним меркам ;-), но это абсолютно не будет быстрее, чем просто выплеснуть его за один прием (в лучшем случае это будет точно то же самое) скорость, возможно, даже немного медленнее, если ваша базовая операционная система и система хранения не справятся с задачей кэширования / буферизации с упреждением чтения. Поэтому я предлагаю:

import fileinput

carnames = open('car_names.txt').readlines()
carnamit = iter(carnames)

skip = False
for line in fileinput.input(['car_descriptions.txt'], True, '.bak'):
  if not skip:
    print line,
  if '@CAR_NAME' in line:
    print next(carnamit),
    skip = True
  else:
    skip = False

Так что измерьте скорость этого, и альтернативу, которая делает

carnamit = open('car_names.txt')

в начале, вместо того, чтобы читать все строки в списке, как моя первая версия - держу пари, что первая версия (в той мере, в которой есть измеримая и воспроизводимая разница) окажется быстрее.

Кстати, модуль ввода файлов стандартной библиотеки задокументирован здесь , и это действительно удобный способ выполнить «виртуальную перезапись на месте» текстовых файлов (обычно сохраняя старую версию в качестве резервной копии, на всякий случай - но даже если машина выйдет из строя в середине операции, старая версия данных все равно будет там, так что в некотором смысле «перезапись» работает атомарно по отношению к сбоям машины, приятное небольшое прикосновение; -.)

1 голос
/ 13 ноября 2009
for line1, line2 in zip(file(filename1), file(filename2)):
    # do your thing

или аналогичный

0 голосов
/ 26 ноября 2009

Я думаю, что это соответствует вопросу:

  • читает файл описания по одной строке за раз
  • когда он видит @CAR_NAME, он все равно его излучает, но заменяет следующую строку в файле описания следующей строкой из файла имен

def merge_car_descriptions(namefile, descrfile):
    names = open(namefile,'r')
    descr = open(descrfile,'r')
    for d in descr:
        if '@CAR_NAME' in d:
            yield d + names.readline()
            descr.next()
        else:
            yield d

if __name__=='__main__':
    import sys
    if len(sys.argv) != 3:
        sys.exit("Syntax: %s car_names.txt car_descriptions.txt" % sys.argv[0])
    for l in merge_car_descriptions(sys.argv[1], sys.argv[2]):
        print l,
0 голосов
/ 13 ноября 2009

12340 - это не какие-либо данные (в том смысле, что на рынке имеется гораздо больше данных для обработки).

Еще лучший подход - использовать модуль build in sqlite. Если нет, используйте какой-нибудь простой формат, например, CSV. Это организованная структура. Если не использовать потоки, вы можете обрабатывать два файла одновременно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...