# Функция open

[open](http://docs.python.org/dev/library/functions.html#open) открывает файл. Логично, правда? Зачастую она используется следующим образом:

```python
f = open('photo.jpg', 'r+')
jpgdata = f.read()
f.close()
```

Причина, по которой я пишу эту главу в том, что я очень часто вижу такой код. В нем **три** ошибки. Сможете найти? Если нет - продолжайте читать. В конце главы вы будете знать наверняка, что не так с кодом выше и, что важнее, сможете избегать подобных проблем в своем коде. Давайте начнем с основ.

`open` возвращает дескриптор файла, полученный Python-приложением от вашей операционной системы. Вам требуется вернуть дескриптор назад, после того как работа с файлом завершена, иначе вы можете упереться в ограничение на количество одновременно открытых дескрипторов.

Явно вызывая `close` вы закрываете дескриптор файла, но только при успешном чтении. При вызове Exception после `f = open(...)` `f.close()` не будет выполнен (в зависимости от интерпретатора Python дескриптор может быть возвращён, но это уже другая история). Чтобы быть уверенным в закрытии файла вне зависимости от потенциальных ошибок необходимо использовать выражение `with`:

```python
with open('photo.jpg', 'r+') as f:
    jpgdata = f.read()
```

Первый аргумент `open` это файл. Второй - (*метод*) определяет *как* файл будет открыт.

* Если вы хотите прочесть файл - `r`
* Для чтения и записи `r+`
* Для перезаписи содержимого файла `w`
* Добавление информации в файл `a`

Существуют и другие методы, но вы их скорее всего никогда не встретите. Метод важен не только из-за изменения поведения, но и поскольку он может привести к ошибкам доступа. Например, если мы хотим открыть jpg файл в директории, защищённой от записи, `open(.., 'r+')` вызовет ошибку. Метод также может содержать один дополнительный символ - мы можем открыть файл в бинарном виде (вы получите строку байтов) или в текстовом (строка символов).

В целом, если формат написан людьми, то вам нужен текстовый метод. `jpg` изображения не пишутся строка за строкой людьми (и не могут читаться ими), поэтому их стоит открывать в бинарном виде, добавляя `b` в метод (если вы следуете примеру выше, то корректным будет `rb`). Если вы открываете что-то в текстовом формате (добавьте `t` или ничего к `r/r+/w/a`) вы также должны знать кодировку. Для компьютера все файлы это наборы байтов, не символов.

К сожалению, `open` не позволяет непосредственно выбирать кодировку в Python 2.x. Тем не менее, [io.open](http://docs.python.org/2/library/io.html#io.open) доступна в обоих ветках Python (в 3.x `open` выступает в качестве алиаса) и делает то, что нам нужно. Вы можете передавать кодировку в аргументе `encoding`. Если вы её не выберете, то система и Python остановятся на кодировке по умолчанию. Вы можете попробовать довериться им, однако стандартный выбор может быть полностью ошибочен или кодировка не сможет отобразить часть символов в файле (такое часто происходит с Python 2.x и Windows). Так что лучше выбирайте её самостоятельно. `utf-8` превосходна и поддерживается большинством браузеров и языков программирования. При записи файла вы можете выбрать любую на свой вкус (или отталкиваясь от предпочтений программы, которая будет этот файл читать).

Как определить кодировку файла, который вы пытаетесь прочесть? К сожалению, нет надежного способа определения правильной кодировки - одни и те же байты могут представлять различные, но разрешенные символы в различных кодировках. По этой причине вам придется опираться на метаданные (например, заголовки HTTP). Все чаще форматы определяют кодировку как UTF-8.

Вооруженные этими знаниями, давайте напишем программу, которая читает файл, определяет является ли он JPG изображением (подсказка: эти файлы начинаются с байтов `FF D8`) и записывает текстовый файл, описывающий входной файл:

```python
import io

with open('photo.jpg', 'rb') as inf:
    jpgdata = inf.read()

if jpgdata.startswith(b'\xff\xd8'):
    text = 'Это JPEG файл (%d байт)\n'
else:
    text = 'Это произвольный файл (%d байт)\n'

with io.open('summary.txt', 'w', encoding='utf-8') as outf:
    outf.write(text % len(jpgdata))
```

Теперь, я уверен, вы будете использовать `open` правильно!


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://pavel-karateev.gitbook.io/intermediate-python/sintaksis/open_function.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
