# 파일 요청 { #request-files }

`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` 임포트 { #import-file }

`fastapi` 에서 `File` 과 `UploadFile` 을 임포트 합니다:

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

## `File` 매개변수 정의 { #define-file-parameters }

`Body` 및 `Form` 과 동일한 방식으로 파일의 매개변수를 생성합니다:

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

/// info | 정보

`File` 은 `Form` 으로부터 직접 상속된 클래스입니다.

하지만 `fastapi`로부터 `Query`, `Path`, `File` 등을 임포트 할 때, 이것들은 특별한 클래스들을 반환하는 함수라는 것을 기억하기 바랍니다.

///

/// tip | 팁

File의 본문을 선언할 때, 매개변수가 쿼리 매개변수 또는 본문(JSON) 매개변수로 해석되는  것을 방지하기 위해 `File` 을 사용해야합니다.

///

파일들은 "폼 데이터"의 형태로 업로드 됩니다.

*경로 처리 함수*의 매개변수를 `bytes` 로 선언하는 경우 **FastAPI**는 파일을 읽고 `bytes` 형태의 내용을 전달합니다.

이것은 전체 내용이 메모리에 저장된다는 것을 의미한다는 걸 염두하기 바랍니다. 이는 작은 크기의 파일들에 적합합니다.

어떤 경우에는 `UploadFile` 을 사용하는 것이 더 유리합니다.

## `UploadFile`을 사용하는 `File` 매개변수 { #file-parameters-with-uploadfile }

`File` 매개변수를 `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>  `async` 인터페이스를 갖고 있습니다.
* file-like object를 필요로하는 다른 라이브러리에 직접적으로 전달할 수 있는 파이썬 <a href="https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile" class="external-link" target="_blank">`SpooledTemporaryFile`</a> 객체를 반환합니다.

### `UploadFile` { #uploadfile }

`UploadFile` 은 다음과 같은 어트리뷰트가 있습니다:

* `filename` : 문자열(`str`)로 된 업로드된 파일의 파일명입니다 (예: `myimage.jpg`).
* `content_type` : 문자열(`str`)로 된 파일 형식(MIME type / media type)입니다 (예: `image/jpeg`).
* `file` :  <a href="https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile" class="external-link" target="_blank">`SpooledTemporaryFile`</a> (a <a href="https://docs.python.org/3/glossary.html#term-file-like-object" class="external-link" target="_blank">file-like</a> object)입니다. 이것은 "file-like" 객체를 필요로하는 다른 함수나 라이브러리에 직접적으로 전달할 수 있는 실질적인 파이썬 파일 객체입니다.

`UploadFile` 에는 다음의 `async` 메소드들이 있습니다. 이들은 내부적인 `SpooledTemporaryFile` 을 사용하여 해당하는 파일 메소드를 호출합니다.

* `write(data)`: `data`(`str` 또는 `bytes`)를 파일에 작성합니다.
* `read(size)`: 파일의 바이트 및 글자의 `size`(`int`)를 읽습니다.
* `seek(offset)`: 파일 내 `offset`(`int`) 위치의 바이트로 이동합니다.
    * 예) `await myfile.seek(0)` 를 사용하면 파일의 시작부분으로 이동합니다.
    * `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 기술 세부사항

**FastAPI**의 `UploadFile` 은 **Starlette**의 `UploadFile` 을 직접적으로 상속받지만, **Pydantic** 및 FastAPI의 다른 부분들과의 호환성을 위해 필요한 부분들이 추가되었습니다.

///

## "폼 데이터"란 { #what-is-form-data }

HTML의 폼들(`<form></form>`)이 서버에 데이터를 전송하는 방식은 대개 데이터에 JSON과는 다른 "특별한" 인코딩을 사용합니다.

**FastAPI**는 JSON 대신 올바른 위치에서 데이터를 읽을 수 있도록 합니다.

/// note | 기술 세부사항

폼의 데이터는 파일이 포함되지 않은 경우 일반적으로 "미디어 유형" `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> web docs for <code>POST</code></a>를 참고하기 바랍니다.

///

/// warning | 경고

다수의 `File` 과 `Form` 매개변수를 한 *경로 처리*에 선언하는 것이 가능하지만, 요청의 본문이 `application/json` 가 아닌 `multipart/form-data` 로 인코딩 되기 때문에 JSON으로 받아야하는 `Body` 필드를 함께 선언할 수는 없습니다.

이는 **FastAPI**의 한계가 아니라, HTTP 프로토콜에 의한 것입니다.

///

## 선택적 파일 업로드 { #optional-file-upload }

표준 타입 애너테이션을 사용하고 기본값을 `None`으로 설정하여 파일을 선택적으로 만들 수 있습니다:

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

## 추가 메타데이터를 포함한 `UploadFile` { #uploadfile-with-additional-metadata }

추가 메타데이터를 설정하기 위해 예를 들어 `UploadFile`과 함께 `File()`을 사용할 수도 있습니다:

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

## 다중 파일 업로드 { #multiple-file-uploads }

여러 파일을 동시에 업로드 할 수 있습니다.

그들은 "폼 데이터"를 사용하여 전송된 동일한 "폼 필드"에 연결됩니다.

이 기능을 사용하기 위해 , `bytes` 의 `List` 또는 `UploadFile` 를 선언하기 바랍니다:

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

선언한대로, `bytes` 의 `list` 또는 `UploadFile` 들을 전송받을 것입니다.

/// note | 기술 세부사항

`from starlette.responses import HTMLResponse` 역시 사용할  수 있습니다.

**FastAPI**는 개발자의 편의를 위해 `fastapi.responses` 와 동일한 `starlette.responses` 도 제공합니다. 하지만 대부분의 응답들은 Starlette로부터 직접 제공됩니다.

///

### 추가 메타데이터를 포함한 다중 파일 업로드 { #multiple-file-uploads-with-additional-metadata }

이전과 같은 방식으로 `UploadFile`에 대해서도 `File()`을 사용해 추가 매개변수를 설정할 수 있습니다:

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

## 요약 { #recap }

`File`, `bytes`, `UploadFile`을 사용하여 폼 데이터로 전송되는 요청에서 업로드할 파일을 선언하세요.
