Прочитайте большой файл .mbox с Python - PullRequest
0 голосов
/ 10 января 2020

Я бы хотел прочитать большой 3GB-файл .mbox из резервной копии Gmail. Это работает:

import mailbox
mbox = mailbox.mbox(r"D:\All mail Including Spam and Trash.mbox")
for i, message in enumerate(mbox):
    print("from   :",message['from'])
    print("subject:",message['subject'])
    if message.is_multipart():
        content = ''.join(part.get_payload(decode=True) for part in message.get_payload())
    else:
        content = message.get_payload(decode=True)
    print("content:",content)
    print("**************************************")

    if i == 10:
        break

за исключением того, что для первых 10 сообщений это занимает более 40 секунд.

Существует ли более быстрый способ доступа к большому файлу .mbox с помощью Python

1 Ответ

1 голос
/ 10 января 2020

Вот быстрая и грязная попытка реализовать генератор для чтения в файле mbox сообщения за сообщением. Я решил просто отбросить информацию из разделителя From; Я предполагаю, что, возможно, реальная библиотека mailbox может предоставить больше информации, и, конечно, она поддерживает только чтение, а не поиск или запись во входной файл.

#!/usr/bin/env python3

import email
from email.policy import default

class MboxReader:
    def __init__(self, filename):
        self.handle = open(filename, 'rb')
        assert self.handle.readline().startswith(b'From ')

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, exc_traceback):
        self.handle.close()

    def __iter__(self):
        return iter(self.__next__())

    def __next__(self):
        lines = []
        while True:
            line = self.handle.readline()
            if line == b'' or line.startswith(b'From '):
                yield email.message_from_bytes(b''.join(lines), policy=default)
                if line == b'':
                    break
                lines = []
                continue
            lines.append(line)

Использование:

with MboxReader(mboxfilename) as mbox:
    for message in mbox:
        print(message.as_string())
...