以下是我一直在处理的应用的一部分。该部分用于使用addValue更新文本文件。起初我认为它正在工作,但接缝增加了更多的线条,而且速度非常慢。
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
所以我的问题是,还有更好的方法吗?我可以将文件加载到内存中(文件大约1Mb)更改所需的行然后保存文件,或者任何人都可以提出另一种方法来加快速度。
感谢您花时间去看。
修改 我已经更改了很多代码,这确实工作得更快,但输出并不像预期的那样,因为某些原因它将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
答案 0 :(得分:0)
Aham - 您在for
循环的每次重复中打开,阅读和重写您的文件 - 每次为每个节目播放一次。整个多重宇宙中的一些东西可能比这慢。
你可以沿着同一条线 - 只需在for循环之前读取所有“文件”一次, 迭代列表读取,并将所有内容写回磁盘,只需一次=
或多或少:
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()
这仍然不是最优的 - 但是你的代码中最少的变化就是停止那么慢的速度。
答案 1 :(得分:0)
您正在重新阅读并重写您追踪的每个节目的每一集的整个文件 - 当然这很慢。不要那样做。相反,请阅读该文件一次。从每一行中解析节目标题,季节和剧集编号(可能使用带有分隔符='\ t'的csv
内置库),看看它们是否在您正在跟踪的集合中。如果是,请进行替换,并以任一方式写入该行。
它看起来像这样:
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)
具体细节取决于文件格式的严格程度 - 您对线条结构的了解越多越好。如果标题,季节和剧集字段的索引不同,可能最好的做法是在表示寻找相关标记的行的列表中迭代一次。
我已跳过错误检查 - 根据您对原始文件的信心,您可能希望确保将季节和剧集编号转换为整数,或将trakt_shows_seen
值字符串化。 csv阅读器将返回编码的字节串,因此如果trakt_shows_seen
中的节目名称是Unicode对象(它们似乎不在您的粘贴代码中),您应该解码csv阅读器的结果或编码字典值。 / p>
我个人可能会将trakt_shows_seen
转换为一组(标题,季节,剧集)元组,以便更方便地检查一行是否感兴趣。至少如果标题,季节和剧集的字段编号是固定的。当我读取输入文件而不是在内存中保留行列表时,我也会写入我的outfile文件(在不同的文件名下);这将允许在覆盖原始输入之前使用shell的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