在当前代码中,您正在将整个文件同时读取到内存中。因为它们是500Mb文件,这意味着500Mb字符串。然后重复替换它们,这意味着Python必须用第一个替换创建一个新的500Mb字符串,然后销毁第一个字符串,然后为第二个替换创建第二个500Mb字符串,然后为每个替换销毁第二个字符串,等等。结果是来回复制了大量数据,更不用说使用大量内存了。
如果知道替换项始终包含在一行中,则可以通过迭代逐行读取文件。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兆字节的字符串。
另一个很大的改进是,如果你能一次完成替换,而不是按顺序尝试一大堆替换。有几种方法可以做到这一点,但哪种方法最合适完全取决于你要用什么来代替什么。对于将单个字符转换为其他字符,unicode对象的translate方法可能很方便。将一个dict映射unicode代码点(作为整数)传递给unicode字符串:>>> u"\xff and \ubd23".translate({0xff: u"255", 0xbd23: u"something else"})
u'255 and something else'
为了替换子字符串(不仅仅是单个字符),可以使用re模块。re.sub函数(以及编译的regexp的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'