протрите папку обмена до указанного размера - PullRequest
0 голосов
/ 06 марта 2019

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

Вот мой пример кода:

def get_foldersize(folder):
    if folder.__class__ != folders.Messages:
        return -1
    return sum(folder.all().values_list('size', flat=True))


def wipe_by_size(folder=account.inbox, size='4.8gb', result_as_str=True):
    """
    Delete all old messages in specified exchange folder to specified size
    size may setted like str ("4,9gb", "500.5 Mb", "1024kB") or like int (means size setted in bytes)
    if result_as_str == True, func returns a stats delete msg, 
    otherwise tuple (deleted_files_count, deleted_bytes, before_files_count, before_bytes, after_files_count, after_bytes)
    """
    if folder.__class__ != folders.Messages:
        raise ValueError("Param 'folder' not a exchange-server folder object!")

    m = {
        'gb': 1024 ** 3,
        'mb': 1024 ** 2,
        'kb': 1024,
    }

    size_bytes = None

    if isinstance(size, str):
        if ',' in size:
            size = size.replace(',', '.')

        for k, v in m.items():
            if k in size.lower():
                size = size.split(k)[0].strip()
                try:
                    size_float = float(size)
                    size_bytes = round(size_float * v)
                except ValueError:
                    raise ValueError(f"Incorrect format of param 'size', recieve '{size_str}'")
                break
        else:
            raise ValueError(
                f"Incorrect format of 'size' param, '{size_str}' must contains int or float number and something from '{list(m.keys())}'")
    elif isinstance(size, (int, float,)):
        size_bytes = int(size)
    else:
        raise ValueError(
            'Parameter "size" can be a str (example:"4,9gb", "500.5 Mb", "1024kB") or int folder size in bytes')

    if get_foldersize(folder) < size_bytes:
        return

    before = folder.total_count
    before_bytes = get_foldersize(folder)

    while get_foldersize(folder) > size_bytes:
        msg = folder.all().order_by('datetime_received')[0]
        try:
            # print(msg.subject, msg.sender)
            msg.delete()
        except Exception as e:
            if msg is not None:
                print(f"wipe_by_size: Can't delete {msg.sender}({msg.subject})")
            else:
                print("wipe_by_size: msg = None")

    after = folder.total_count
    deleted = before - after

    after_bytes = get_foldersize(folder)
    deleted_bytes = before_bytes - after_bytes

    if result_as_str:
        return f"""Wiped {deleted} file(s), freed {'{0:12,d}'.format(
            deleted_bytes)} bytes. Before: {before} files, {'{0:12,d}'.format(
            before_bytes)} bytes. After: {after} files, {'{0:12,d}'.format(after_bytes)} bytes"""

    return deleted, deleted_bytes, before, before_bytes, after, after_bytes


delete_msg = wipe_by_size(folder=account.sent, size='4,8gb')
deleted, deleted_bytes, before, before_bytes, after, after_bytes = wipe_by_size(folder=account.sent, size='4,8gb')

Функция работает, но оченьмедленно - медленно, потому что get_foldersize() вызывается для каждой итерации цикла while.

Я предлагаю получить все сообщения в папке в обратном порядке (как сейчас), сохранить размер каждого сообщения,затем подсчитайте, сколько и какие сообщения мне нужно стереть, и удалите их все за один раз.Я думаю, что будет быстрее.Но я не знаю, как (и если это возможно?) Получить размер сообщения.

1 Ответ

0 голосов
/ 07 марта 2019

Размер сообщения содержится в поле size, как вы узнали.Таким образом, вы можете рассчитать размер папки один раз, а затем прочитать msg.size и уменьшить общий размер папки в цикле.Наконец, уменьшите сетевой трафик, получая только поле size каждого сообщения в папке:

class FolderSize(ExtendedProperty):
    property_tag = 0x0e08
    property_type = 'Integer'

Folder.register('size', FolderSize)

folder = account.inbox
folder_size = folder.size
max_size = 123456789  # Bytes

for msg in folder.all().only('size'):
    if folder_size <= max_size:
        break
    msg.delete()
    folder_size -= msg.size
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...