> **Источник:** https://python-all.ru/2.7/library/multifile.html
>
> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.

---

# 18.10. [`multifile`](https://python-all.ru/2.7/library/multifile.html#module-multifile) – поддержка файлов, содержащих отдельные части

Устарело с версии 2.5: Следует использовать пакет [`email`](https://python-all.ru/2.7/library/email.html#module-email) вместо модуля [`multifile`](https://python-all.ru/2.7/library/multifile.html#module-multifile). Этот модуль присутствует только для сохранения обратной совместимости.

Объект [`MultiFile`](https://python-all.ru/2.7/library/multifile.html#multifile.MultiFile) позволяет обрабатывать разделы текстового файла как файлоподобные объекты ввода, при этом `''` возвращается [`readline()`](https://python-all.ru/2.7/library/readline.html#module-readline) при обнаружении заданного шаблона-разделителя. Значения по умолчанию этого класса предназначены для использования при разборе MIME-сообщений с несколькими частями, но с помощью создания подкласса и переопределения методов его можно легко адаптировать для более общего использования.

#### `class multifile.MultiFile(fp[, seekable])`

Создаёт multi-file. Необходимо создать экземпляр этого класса с аргументом – объектом ввода, из которого экземпляр [`MultiFile`](https://python-all.ru/2.7/library/multifile.html#multifile.MultiFile) будет получать строки, например, файловым объектом, возвращаемым [`open()`](https://python-all.ru/2.7/library/functions.html#open).

[`MultiFile`](https://python-all.ru/2.7/library/multifile.html#multifile.MultiFile) всегда использует только методы [`readline()`](https://python-all.ru/2.7/library/readline.html#module-readline), [`seek()`](https://python-all.ru/2.7/library/multifile.html#multifile.MultiFile.seek) и [`tell()`](https://python-all.ru/2.7/library/multifile.html#multifile.MultiFile.tell) входного объекта, причём последние два нужны только для произвольного доступа к отдельным MIME-частям. Чтобы использовать [`MultiFile`](https://python-all.ru/2.7/library/multifile.html#multifile.MultiFile) с непозиционируемым потоковым объектом, установите необязательный аргумент *seekable* в false; это предотвратит использование методов [`seek()`](https://python-all.ru/2.7/library/multifile.html#multifile.MultiFile.seek) и [`tell()`](https://python-all.ru/2.7/library/multifile.html#multifile.MultiFile.tell) входного объекта.

Полезно знать, что в представлении [`MultiFile`](https://python-all.ru/2.7/library/multifile.html#multifile.MultiFile) текст состоит из трёх видов строк: данных, разделителей разделов и конечных маркеров. MultiFile предназначен для поддержки разбора сообщений, которые могут содержать несколько вложенных частей, каждая со своим шаблоном строк-разделителей и конечных маркеров.

> **См. также**
>
> **Модуль [`email`](https://python-all.ru/2.7/library/email.html#module-email)**
>
> Комплексный пакет для обработки электронной почты; заменяет модуль [`multifile`](https://python-all.ru/2.7/library/multifile.html#module-multifile).

## 18.10.1. Объекты MultiFile

Экземпляр [`MultiFile`](https://python-all.ru/2.7/library/multifile.html#multifile.MultiFile) имеет следующие методы:

#### `MultiFile.readline(str)`

Читает строку. Если строка является данными (не разделителем раздела, не конечным маркером и не реальным концом файла), возвращает её. Если строка соответствует самой последней помещённой в стек границе, возвращает `''` и устанавливает `self.last` в 1 или 0 в зависимости от того, является ли совпадение конечным маркером. Если строка соответствует любой другой границе из стека, вызывает исключение. При достижении конца файла в нижележащем потоковом объекте метод вызывает `Error`, если только все границы не были извлечены из стека.

#### `MultiFile.readlines(str)`

Возвращает все строки, оставшиеся в этой части, в виде списка строк.

#### `MultiFile.read()`

Читает все строки до следующего раздела. Возвращает их в виде одной (многострочной) строки. Обратите внимание: этот метод не принимает аргумент размера!

#### `MultiFile.seek(pos[, whence])`

Позиционирование. Индексы позиционирования задаются относительно начала текущего раздела. Аргументы *pos* и *whence* интерпретируются так же, как при позиционировании в файле.

#### `MultiFile.tell()`

Возвращает позицию в файле относительно начала текущего раздела.

#### `MultiFile.next()`

Пропускает строки до следующего раздела (то есть читает строки, пока не будет поглощён разделитель раздела или конечный маркер). Возвращает true, если такой раздел существует, и false, если обнаружен конечный маркер. Повторно активирует самую последнюю помещённую границу.

#### `MultiFile.is_data(str)`

Возвращает true, если *str* является данными, и false, если это может быть границей раздела. В текущей реализации проверяет, не начинается ли строка с префикса `'-``-'` (который есть у всех MIME-границ), но объявлена так, чтобы её можно было переопределить в производных классах.

Обратите внимание: эта проверка используется как быстрый предохранитель перед настоящими проверками границ; если она всегда возвращает false, это лишь замедлит обработку, но не приведёт к сбою.

#### `MultiFile.push(str)`

Помещает строку границы в стек. Когда во входной строке встречается оформленная версия этой границы, она интерпретируется как разделитель раздела или конечный маркер (в зависимости от оформления, см. [**RFC 2045**](https://python-all.ru/2.7/library/multifile.html)). Все последующие чтения будут возвращать пустую строку, указывая на конец файла, пока вызов [`pop()`](https://python-all.ru/2.7/library/multifile.html#multifile.MultiFile.pop) не удалит границу, или вызов [`next()`](https://python-all.ru/2.7/library/multifile.html#multifile.MultiFile.next) не активирует её повторно.

Можно поместить в стек несколько границ. Обнаружение самой последней помещённой границы вернёт EOF; обнаружение любой другой границы вызовет исключение.

#### `MultiFile.pop()`

Извлекает границу раздела из стека. Эта граница больше не будет интерпретироваться как EOF.

#### `MultiFile.section_divider(str)`

Преобразует границу в строку-разделитель раздела. По умолчанию этот метод добавляет в начало `'--'` (который есть у MIME-границ разделов), но объявлен так, чтобы его можно было переопределить в производных классах. Этот метод не должен добавлять LF или CR-LF, так как сравнение результата игнорирует завершающие пробельные символы.

#### `MultiFile.end_marker(str)`

Преобразует строку границы в строку конечного маркера. По умолчанию этот метод добавляет в начало `'--'` и в конец `'--'` (как маркер конца сообщения MIME-многокомпонентного сообщения), но объявлен так, чтобы его можно было переопределить в производных классах. Этот метод не должен добавлять LF или CR-LF, так как сравнение результата игнорирует завершающие пробельные символы.

Наконец, экземпляры [`MultiFile`](https://python-all.ru/2.7/library/multifile.html#multifile.MultiFile) имеют две открытые переменные экземпляра:

#### `MultiFile.level`

Глубина вложенности текущей части.

#### `MultiFile.last`

True, если последний конец файла был маркером конца сообщения.

## 18.10.2. [`MultiFile`](https://python-all.ru/2.7/library/multifile.html#multifile.MultiFile) Пример

```python
import mimetools
import multifile
import StringIO

def extract_mime_part_matching(stream, mimetype):
    """Возвращает первый элемент многочастного MIME-сообщения в потоке
    соответствующий MIME-тип."""

    msg = mimetools.Message(stream)
    msgtype = msg.gettype()
    params = msg.getplist()

    data = StringIO.StringIO()
    if msgtype[:10] == "multipart/":

        file = multifile.MultiFile(stream)
        file.push(msg.getparam("boundary"))
        while file.next():
            submsg = mimetools.Message(file)
            try:
                data = StringIO.StringIO()
                mimetools.decode(file, data, submsg.getencoding())
            except ValueError:
                continue
            if submsg.gettype() == mimetype:
                break
        file.pop()
    return data.getvalue()
```
