В вашем текущем коде вы читаете весь файл в память одновременно.Так как это файлы размером 500 МБ, это означает, что строки размером 500 МБ.И затем вы выполняете их повторную замену, что означает, что Python должен создать новую строку размером 500 МБ с первой заменой, затем уничтожить первую строку, затем создать вторую строку размером 500 МБ для второй замены, а затем уничтожить вторую строку и так далее,за каждую замену.Это оказывается довольно много копирования данных туда и обратно, не говоря уже об использовании большого количества памяти.
Если вы знаете, что замены всегда будут содержаться в строке, вы можете прочитать строку файлапострочно, перебирая его.Python буферизует чтение, что означает, что оно будет довольно оптимизировано.Вам следует открыть новый файл под новым именем для одновременной записи нового файла.Выполняйте замену по очереди в каждой строке и сразу же записывайте ее.Это значительно уменьшит объем используемой памяти и объем памяти, копируемой назад и вперед при замене:
for file in files:
fname = os.path.join(dir, file)
inFile = codecs.open(fname, "r", "utf-8")
outFile = codecs.open(fname + ".new", "w", "utf-8")
for line in inFile:
newline = do_replacements_on(line)
outFile.write(newline)
inFile.close()
outFile.close()
os.rename(fname + ".new", fname)
Если вы не можете быть уверены, что они 'всегда буду на одной линии, все становится немного сложнее;вам придется читать в блоках вручную, используя inFile.read(blocksize)
, и внимательно следить за тем, возможно ли частичное совпадение в конце блока.Это не так просто сделать, но обычно все же стоит избегать строк размером 500 МБ.
Еще одним большим улучшением было бы то, что вы могли бы выполнять замены за один раз, вместо того, чтобы пытаться выполнить целую кучу замен по порядку.Есть несколько способов сделать это, но то, что подходит лучше всего, полностью зависит от того, что вы заменяете и на что.Для перевода отдельных символов во что-то еще может быть удобен метод translate
объектов Unicode.Вы передаете его в кодировке Unicode (в виде целых чисел) в строки Unicode:
>>> u"\xff and \ubd23".translate({0xff: u"255", 0xbd23: u"something else"})
u'255 and something else'
Для замены подстрок (а не только отдельных символов) вы можете использовать модуль re
.Функция re.sub
(и метод скомпилированных регулярных выражений sub
) может принимать вызываемый объект (функцию) в качестве первого аргумента, который затем будет вызываться для каждого совпадения:
>>> import re
>>> d = {u'spam': u'spam, ham, spam and eggs', u'eggs': u'saussages'}
>>> p = re.compile("|".join(re.escape(k) for k in d))
>>> def repl(m):
... return d[m.group(0)]
...
>>> p.sub(repl, u"spam, vikings, eggs and vikings")
u'spam, ham, spam and eggs, vikings, saussages and vikings'