# Запит файлів

Ви можете визначити файли, які будуть завантажуватися клієнтом, використовуючи `File`.

/// info | Інформація

Щоб отримувати завантажені файли, спочатку встановіть <a href="https://github.com/Kludex/python-multipart" class="external-link" target="_blank">python-multipart</a>.

Переконайтеся, що Ви створили [віртуальне середовище](../virtual-environments.md){.internal-link target=_blank}, активували його та встановили пакет, наприклад:

```console
$ pip install python-multipart
```

Це необхідно, оскільки завантажені файли передаються у вигляді "форматованих даних форми".

///

## Імпорт `File`

Імпортуйте `File` та `UploadFile` з `fastapi`:

{* ../../docs_src/request_files/tutorial001_an_py39.py hl[3] *}

## Визначення параметрів `File`

Створіть параметри файлів так само як Ви б створювали `Body` або `Form`:

{* ../../docs_src/request_files/tutorial001_an_py39.py hl[9] *}

/// info | Інформація

`File`  — це клас, який безпосередньо успадковує `Form`.

Але пам’ятайте, що коли Ви імпортуєте `Query`, `Path`, `File` та інші з `fastapi`, це насправді функції, які повертають спеціальні класи.

///

/// tip | Підказка

Щоб оголосити тіла файлів, Вам потрібно використовувати `File`, тому що інакше параметри будуть інтерпретовані як параметри запиту або параметри тіла (JSON).

///

Файли будуть завантажені у вигляді "форматованих даних форми".

Якщо Ви оголосите тип параметра функції обробника маршруту як `bytes`, **FastAPI** прочитає файл за Вас, і Ви отримаєте його вміст у вигляді `bytes`.

Однак майте на увазі, що весь вміст буде збережено в пам'яті. Це працюватиме добре для малих файлів.

Але в деяких випадках Вам може знадобитися `UploadFile`.

## Параметри файлу з `UploadFile`

Визначте параметр файлу з типом `UploadFile`:

{* ../../docs_src/request_files/tutorial001_an_py39.py hl[14] *}

Використання `UploadFile` має кілька переваг перед `bytes`:

* Вам не потрібно використовувати `File()` у значенні за замовчуванням параметра.
* Використовується "буферизований" файл:
    * Файл зберігається в пам'яті до досягнення певного обмеження, після чого він записується на диск.
* Це означає, що він добре працює для великих файлів, таких як зображення, відео, великі двійкові файли тощо, не споживаючи всю пам'ять.
Ви можете отримати метадані про завантажений файл.
* Він має <a href="https://docs.python.org/3/glossary.html#term-file-like-object" class="external-link" target="_blank">file-like</a> `асинхронний файловий інтерфейс` interface.
* Він надає фактичний об'єкт Python <a href="https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile" class="external-link" target="_blank">`SpooledTemporaryFile`</a>, який можна передавати безпосередньо іншим бібліотекам.

### `UploadFile`

`UploadFile` має такі атрибути:

* `filename`: Рядок `str` з оригінальною назвою файлу, який був завантажений (наприклад, `myimage.jpg`).
* `content_type`: Рядок `str` з MIME-типом (наприклад, `image/jpeg`).
* `file`: Об'єкт <a href="https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile" class="external-link" target="_blank">SpooledTemporaryFile</a> (<a href="https://docs.python.org/3/glossary.html#term-file-like-object" class="external-link" target="_blank">файлоподібний</a> об'єкт). Це фактичний файловий об'єкт Python, який можна безпосередньо передавати іншим функціям або бібліотекам, що очікують "файлоподібний" об'єкт.

`UploadFile` має такі асинхронні `async` методи. Вони викликають відповідні методи файлу під капотом (використовуючи внутрішній `SpooledTemporaryFile`).

* `write(data)`: Записує `data` (`str` або `bytes`) у файл.
* `read(size)`: Читає `size` (`int`) байтів/символів з файлу.
* `seek(offset)`: Переміщується до позиції `offset` (`int`) у файлі.
    * Наприклад, `await myfile.seek(0)` поверне курсор на початок файлу.
    * This is especially useful if you run `await myfile.read()` once and then need to read the contents again. Це особливо корисно, якщо Ви виконуєте await `await myfile.read()` один раз, а потім потрібно знову прочитати вміст.
* `close()`: Закриває файл.

Оскільки всі ці методи є асинхронними `async`, Вам потрібно використовувати "await":

Наприклад, всередині `async` *функції обробки шляху* Ви можете отримати вміст за допомогою:

```Python
contents = await myfile.read()
```
Якщо Ви знаходитесь у звичайній `def` *функції обробки шляху*, Ви можете отримати доступ до `UploadFile.file` безпосередньо, наприклад:

```Python
contents = myfile.file.read()
```

/// note | Технічні деталі `async`

Коли Ви використовуєте `async` методи, **FastAPI** виконує файлові операції у пулі потоків та очікує їх завершення.

///

/// note | Технічні деталі Starlette

`UploadFile` у **FastAPI** успадковується безпосередньо від `UploadFile` у **Starlette**, але додає деякі необхідні частини, щоб зробити його сумісним із **Pydantic** та іншими компонентами FastAPI.

///

## Що таке "Form Data"

Спосіб, у який HTML-форми (`<form></form>`) надсилають дані на сервер, зазвичай використовує "спеціальне" кодування, відмінне від JSON.

**FastAPI**  забезпечує правильне зчитування цих даних з відповідної частини запиту, а не з JSON.

/// note | Технічні деталі

Дані з форм зазвичай кодуються за допомогою "media type" `application/x-www-form-urlencoded`, якщо вони не містять файлів.

Але якщо форма містить файли, вона кодується у форматі `multipart/form-data`. Якщо Ви використовуєте `File`, **FastAPI**  визначить, що потрібно отримати файли з відповідної частини тіла запиту.

Щоб дізнатися більше про ці типи кодування та формові поля, ознайомтеся з <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank"><abbr title="Mozilla Developer Network">документацією MDN</abbr> щодо <code>POST</code></a>.

///

/// warning | Увага

Ви можете оголосити кілька параметрів `File` і `Form` в *операції шляху*, але Ви не можете одночасно оголошувати поля `Body`, які мають надходити у форматі JSON, оскільки тіло запиту буде закодоване у форматі `multipart/form-data`, а не `application/json`.

Це не обмеження **FastAPI**, а особливість протоколу HTTP.

///

## Опціональне Завантаження Файлів

Файл можна зробити необов’язковим, використовуючи стандартні анотації типів і встановлюючи значення за замовчуванням `None`:

{* ../../docs_src/request_files/tutorial001_02_an_py310.py hl[9,17] *}

## `UploadFile` із Додатковими Мета Даними

Ви також можете використовувати `File()` разом із `UploadFile`, наприклад, для встановлення додаткових метаданих:

{* ../../docs_src/request_files/tutorial001_03_an_py39.py hl[9,15] *}

## Завантаження Кількох Файлів

Можна завантажувати кілька файлів одночасно.

Вони будуть пов’язані з одним і тим самим "form field", який передається у вигляді "form data".

Щоб це реалізувати, потрібно оголосити список `bytes` або `UploadFile`:

{* ../../docs_src/request_files/tutorial002_an_py39.py hl[10,15] *}

Ви отримаєте, як і було оголошено, `list` із `bytes` або `UploadFile`.

/// note | Технічні деталі

Ви також можете використати `from starlette.responses import HTMLResponse`.

**FastAPI**  надає ті ж самі `starlette.responses`, що й `fastapi.responses`, для зручності розробників. Однак більшість доступних відповідей надходять безпосередньо від Starlette.

///

### Завантаження декількох файлів із додатковими метаданими

Так само як і раніше, Ви можете використовувати `File()`, щоб встановити додаткові параметри навіть для `UploadFile`:

{* ../../docs_src/request_files/tutorial003_an_py39.py hl[11,18:20] *}

## Підсумок

Використовуйте `File`, `bytes`та `UploadFile`, щоб оголошувати файли для завантаження у запитах, які надсилаються у вигляді form data.
