Мне нравится принятый ответ: он прост и сделает работу. Я также хотел бы предложить альтернативную реализацию:
def chunks(filename, buffer_size=4096):
"""Reads `filename` in chunks of `buffer_size` bytes and yields each chunk
until no more characters can be read; the last chunk will most likely have
less than `buffer_size` bytes.
:param str filename: Path to the file
:param int buffer_size: Buffer size, in bytes (default is 4096)
:return: Yields chunks of `buffer_size` size until exhausting the file
:rtype: str
"""
with open(filename, "rb") as fp:
chunk = fp.read(buffer_size)
while chunk:
yield chunk
chunk = fp.read(buffer_size)
def chars(filename, buffersize=4096):
"""Yields the contents of file `filename` character-by-character. Warning:
will only work for encodings where one character is encoded as one byte.
:param str filename: Path to the file
:param int buffer_size: Buffer size for the underlying chunks,
in bytes (default is 4096)
:return: Yields the contents of `filename` character-by-character.
:rtype: char
"""
for chunk in chunks(filename, buffersize):
for char in chunk:
yield char
def main(buffersize, filenames):
"""Reads several files character by character and redirects their contents
to `/dev/null`.
"""
for filename in filenames:
with open("/dev/null", "wb") as fp:
for char in chars(filename, buffersize):
fp.write(char)
if __name__ == "__main__":
# Try reading several files varying the buffer size
import sys
buffersize = int(sys.argv[1])
filenames = sys.argv[2:]
sys.exit(main(buffersize, filenames))
Код, который я предлагаю, по сути та же идея, что и ваш принятый ответ: прочитайте указанное количество байтов из файла. Разница в том, что сначала он читает хороший кусок данных (4006 - хорошее значение по умолчанию для X86, но вы можете попробовать 1024 или 8192; любой кратный размеру вашей страницы), а затем он возвращает символы в этом блоке по одному.
Код, который я представляю, может быть быстрее для больших файлов. Взять, к примеру, весь текст «Войны и мира» Толстого . Вот мои результаты синхронизации (Mac Book Pro, использующий OS X 10.7.4; so.py - это имя, которое я дал коду, который вставил):
$ time python so.py 1 2600.txt.utf-8
python so.py 1 2600.txt.utf-8 3.79s user 0.01s system 99% cpu 3.808 total
$ time python so.py 4096 2600.txt.utf-8
python so.py 4096 2600.txt.utf-8 1.31s user 0.01s system 99% cpu 1.318 total
Теперь: не принимайте размер буфера в 4096
как универсальную истину; посмотрите на результаты, которые я получаю для разных размеров (размер буфера (в байтах) и время стены (с)):
2 2.726
4 1.948
8 1.693
16 1.534
32 1.525
64 1.398
128 1.432
256 1.377
512 1.347
1024 1.442
2048 1.316
4096 1.318
Как вы можете видеть, вы можете начать видеть выигрыш раньше (и мои сроки, вероятно, очень неточны); размер буфера является компромиссом между производительностью и памятью. Значение по умолчанию 4096 - это просто разумный выбор, но, как всегда, сначала измерьте.