2013-08-10 2 views
0

Ниже приведен раздел приложения, над которым я работаю. Раздел используется для обновления текстового файла с помощью addValue. Сначала я думал, что он работает, но он швы, чтобы добавить больше строк, а также очень медленно.Как ускорить разбор файлов в python?

trakt_shows_seen является словарем шоу, 1 показать раздел выглядит

{'episodes': [{'season': 1, 'playcount': 0, 'episode': 1}, {'season': 1, 'playcount': 0, 'episode': 2}, {'season': 1, 'playcount': 0, 'episode': 3}], 'title': 'The Ice Cream Girls'} 

В этом разделе следует искать для каждого заголовка, сезона и эпизода в файле и когда нашли чек, если он имеет просматриваемой маркер (checkValue) если он это делает, он изменяет его на addvalue, если он не добавляет addValue в конец строки.

Строка из файла

_F /share/Storage/NAS/Videos/Tv/The Ice Cream Girls/Season 01/The Ice Cream Girls - S01E01 - Episode 1.mkv _ai Episode 1 _e 1 _r 6.5 _Y 71 _s 1 _DT 714d861 _et Episode 1 _A 4379,4376,4382,4383 _id 2551 _FT 714d861 _v c0=h264,f0=25,h0=576,w0=768 _C T _IT 717ac9d _R GB: _m 1250 _ad 2013-04-19 _T The Ice Cream Girls _G d _U thetvdb:268910 imdb:tt2372806 _V HDTV 

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

Спасибо, что нашли время посмотреть.

EDIT Я изменил код довольно много, и это делает работу намного быстрее, но выход не как ожидалось, по какой-то причине он пишет lines_of_interest в файл, даже если там нет кода, чтобы сделать это ??

Я еще не добавил какие-либо параметры кодировки, но поскольку файл находится в utf-8, я подозреваю, что будет проблема с акцентированными заголовками.

if trakt_shows_seen: 
     addValue = "\t_w\t1\t" 
     replacevalue = "\t_w\t0\t" 
     with open(OversightFile, 'rb') as infile: 
      p = '\t_C\tT\t' 
      for line in infile: 
       if p in line: 
        tv_offset = infile.tell() - len(line) - 1#Find first TV in file, search from here 
        break 

      lines_of_interest = set() 
      for show_dict in trakt_shows_seen: 
       for episode in show_dict['episodes']: 
        p = re.compile(r'\t_s\t('+str(episode["season"])+')\t.*\t_T\t('+show_dict["title"]+')\t.*\t_e\t('+str(episode["episode"])+')\t') 
        infile.seek(tv_offset)#search from first Tv show 
        for line in infile: 
         if p.findall(line): 
          search_offset = infile.tell() - len(line) - 1 
          lines_of_interest.add(search_offset)#all lines that need to be changed 
     with open(OversightFile, 'rb+') as outfile: 
      for lines in lines_of_interest: 
       for change_this in outfile: 
        outfile.seek(lines) 
        if replacevalue in change_this: 
         change_this = change_this.replace(replacevalue, addValue) 
         outfile.write(change_this) 
         break#Only check 1 line 
        elif not addValue in change_this: 
         #change_this.extend(('_w', '1')) 
         change_this = change_this.replace("\t\n", addValue+"\n") 
         outfile.write(change_this) 
         break#Only check 1 line 
+1

Вы пытаетесь использовать плоский файл в качестве базы данных? –

+0

Файл используется в качестве базы данных другим приложением, но поскольку он по существу является текстовым файлом, я рассматривал его как таковой. Если есть лучший способ, я был бы очень полезен для любых советов. – jhmiller

+1

Если вы выполняете много операций вставки/обновления. Я предлагаю вам использовать базу данных (возможно, SQLite) для выполнения вставок, а затем реализовать функцию «экспорта», которая делает SELECT * в вашей таблице и выгружает результат в файл. –

ответ

0

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

Вы CANGO вдоль той же линии, - только что прочитал все ваши «файл» один раз, прежде чем для петель, итерация по списку читать и писать все обратно на диск, только один раз = более или менее

:

if trakt_shows_seen: 
    addValue = "\t_w\t1\t" 
    checkvalue = "\t_w\t0\t" 
    print ' %s TV shows episodes playcount will be updated on Oversight' % len(trakt_shows_seen) 
    myfile_list = open(file).readlines() 
    for show in trakt_shows_seen: 
     print ' --> ' + show['title'].encode('utf-8') 
     for episode in show['episodes']: 
      print '  Season %i - Episode %i' % (episode['season'], episode['episode']) 
      p = re.compile(r'\t_s\t('+str(episode["season"])+')\t.*\t_T\t('+show["title"]+')\t.*\t_e\t('+str(episode["episode"])+')\t') 
      newList = [] 

      for line in myfile_list: 
       if p.findall(line) : 
        if checkvalue in line: 
         line = line.replace(checkvalue, addValue) 
        elif not addValue in line: 
         line = line.strip("\t\n") + addValue+"\n" 
       newList.append(line) 
      myfile_list = newlist 

    outref = open(file,'w') 
    outref.writelines(newList) 
    outref.close() 

Это еще далеко от оптимального - но является наименее amoutn изменения в коде, чтобы остановить то, что замедляя его так много.

0

Вы перечитываете и переписываете весь свой файл для каждого эпизода каждого шоу, которое вы отслеживаете - это, конечно, медленно. Не делай этого. Вместо этого прочитайте файл один раз. Разбирайте названия шоу и сезонные и эпизодные номера из каждой строки (возможно, используя встроенную библиотеку csv с разделителем = '\ t') и посмотрите, находятся ли они в наборе, который вы отслеживаете. Сделайте свою замену, если они есть, и напишите строку в любом случае.

Это будет выглядеть примерно так:

title_index = # whatever column number has the show title 
season_index = # whatever column number has the season number 
episode_index = # whatever column number has the episode number 

with open('somefile', 'rb') as infile: 
    reader = csv.reader(infile, delimiter='\t') 
    modified_lines = [] 
    for line in reader: 
     showtitle = line[title_index] 
     if showtitle in trakt_shows_seen: 
      season_number = int(line[season_index]) 
      episode_number = int(line[episode_index]) 
      if any((x for x in trakt_shows_seen[showtitle] if x['season'] = season_number and x['episode'] = episode_number)): 
       # line matches a tracked episode 
       watch_count_index = line.index('_w') 
       if watch_count_index != -1: 
        # possible check value found - you may be able to skip straight to assigning the next element to '1' 
        if line[watch_count_index + 1] == '0': 
         # check value found, replace 
         line[watch_count_index + 1] = '1' 
        elif line[watch_count_index + 1] != '1': 
         # not sure what you want to do if something like \t_w\t2\t is present 
         line[watch_count_index + 1] = '1' 
       else: 
        line.extend(('_w', '1')) 
     modified_lines.append(line) 
with open('somefile', 'wb') as outfile: 
    writer = csv.writer(outfile, delimiter='\t') 
    writer.writerows(modified_lines) 

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

Я пропустил проверку ошибок - в зависимости от вашей уверенности в исходном файле вы можете убедиться, что номера сезонов и эпизодов могут быть преобразованы в int или строятся ваши значения trakt_shows_seen. Считыватель csv вернет закодированные байты, поэтому, если отображаемые имена в trakt_shows_seen являются объектами Unicode (которые, как представляется, не находятся в вашем вставленном коде), вы должны либо декодировать результаты чтения csv, либо кодировать значения словаря.

Я лично, вероятно, конвертировал бы trakt_shows_seen в набор (заголовок, сезон, эпизод) кортежей, для более удобной проверки, чтобы узнать, интересует ли линия. По крайней мере, если указаны номера полей для названия, сезона и эпизода. Я также написал бы файл outfile (под другим именем файла), когда я прочитал входной файл, а не сохранил список строк в памяти; что позволило бы провести некоторую проверку работоспособности, скажем, с помощью утилиты diff для оболочки, прежде чем перезаписать исходный вход.

Чтобы создать набор из существующего словаря - в какой-то мере это зависит от того, какой формат использует trakt_shows_seen. Ваш пример показывает запись для одного шоу, но не указывает, как он представляет более одного шоу. Пока я собираюсь предположить, что это список таких словарей, основанный на вашем запрограммированном коде.

shows_of_interest = set() 
for show_dict in trakt_shows_seen: 
    title = show_dict['title'] 
    for episode_dict in show_dict['episodes']: 
     shows_of_interest.add((title, episode_dict['season'], episode_dict['episode'])) 

Затем в цикле, который считывает файл:

 # the rest as shown above    
     season_number = int(line[season_index]) 
     episode_number = int(line[episode_index]) 
     if (showtitle, season_number, episode_number) in shows_of_interest: 
      # line matches a tracked episode 
+0

Я еще не пробовал вас, но считаю, что я пробовал первый, где первый файл был прочитан, но это было так же медленно. Я не уверен, что вы подразумеваете, перейдя на замороженные кортежи, это то, что для проверки того, нужно ли менять этот сезон и эпизод? если это так, его не нужно, так как trakt_shows_seen будет содержать только элементы, которые нуждаются в изменении. – jhmiller

+0

Дело в том, что запись 'if (show, season, episode) в trakt_shows_seen_as_tuples:' быстрее, чем повторение по списку словарей для показа. –

+0

Я бы очень хотел попробовать, но я боюсь. Я считаю, мне нужно создавать кортежи вместо словаря, но поскольку я никогда не использовал кортежи, прежде чем я не могу понять, какой формат использовать. Я могу ссылаться на раздел, который делает trackt_shows_seen, чтобы вы могли добывать, чтобы увидеть, можно ли сделать trakt_shows_seen_tuples. – jhmiller

Смежные вопросы