Как ставить бинарный файл на дозапись питон
Бинарные файлы в отличие от текстовых хранят информацию в виде набора байт. Для работы с ними в Python необходим встроенный модуль pickle . Этот модуль предоставляет два метода:
dump(obj, file) : записывает объект obj в бинарный файл file
load(file) : считывает данные из бинарного файла в объект
При открытии бинарного файла на чтение или запись также надо учитывать, что нам нужно применять режим «b» в дополнение к режиму записи («w») или чтения («r»). Допустим, надо надо сохранить два объекта:
С помощью функции dump последовательно записываются два объекта. Поэтому при чтении файла также последовательно посредством функции load мы можем считать эти объекты. Консольный вывод программы:
Подобным образом мы можем сохранять и извлекать из файла наборы объектов:
В зависимости от того, какой объект мы записывали функцией dump, тот же объект будет возвращен функцией load при считывании файла.
Бинарные файлы. Примеры работы с бинарными файлами
В данной теме показано как можно сохранять данные в бинарных файлах без использования стандартных средств pickle или struct языка Python.
Содержание
- 1. Понятие о бинарных файлах. Представление информации в бинарных файлах
- 2. Запись/чтение списка, который содержит вещественные числа. Пример
- 3. Запись/чтение кортежа, содержащего строки символов. Пример
- 4. Запись/чтение множества, содержащего вещественные числа. Пример
- 5. Запись/чтение двумерной матрицы строк заданного размера. Пример
- 6. Запись/чтение словаря. Пример
- 7. Копирование одного бинарного файла в другой
- 8. Объединение двух бинарных файлов
Поиск на других ресурсах:
1. Понятие о бинарных файлах. Представление информации в бинарных файлах
В языке Python существуют средства для работы с бинарными или двоичными файлами. Бинарные файлы используют строки типа bytes . Это значит при чтении бинарных данных из файла возвращается объект типа bytes .
Открытие бинарного файла осуществляется с помощью функции open() , параметр mode которой содержит символ ‘b’ . Более подробно об открытии/закрытии бинарных файлов описывается здесь .
В отличие от текстовых, бинарные файлы не выполняют преобразования символов конца строки ‘\n’ .
Пример, демонстрирующий особенности представления информации в бинарных файлах.
Результат работы программы
На основании примера выше можно сделать следующие выводы:
- строка бинарных данных выводится как строка;
- отдельный символ (элемент) бинарных данных представлен в виде 8-битных целых чисел.
2. Запись/чтение списка, который содержит вещественные числа. Пример
Результат работы программы
3. Запись/чтение кортежа, содержащего строки символов. Пример
В данном примере строки символов в бинарном файле разделяются символом ‘\n’ . Таким образом, можно записывать и читать информацию без потери ее структуры.
Результат работы программы
4. Запись/чтение множества, содержащего вещественные числа. Пример
Множество, которое содержит только однотипные объекты можно записать в файл. В данном примере записывается множество вещественных чисел.
Результат работы программы
Вид файла myfile6.bin
5. Запись/чтение двумерной матрицы строк заданного размера. Пример
В примере матрица представлена в виде списка.
Результат работы программы
Вид файла myfile7.txt
6. Запись/чтение словаря. Пример
Пусть задан некоторый словарь, который нужно записать в бинарный файл.
Результат работы программы
Вид файла myfile8.txt
7. Копирование одного бинарного файла в другой
8. Объединение двух бинарных файлов. Пример
В примере реализована операция объединения двух файлов в результирующий третий файл. Сначала данные с файлов-источников считываются в списки. Затем происходит конкатенация этих списков и запись результирующего списка в файл результата.
Name already in use
py_training_ru / lecture_08.md
- Go to file T
- Go to line L
- Copy path
- Copy permalink
- Open with Desktop
- View raw
- Copy raw contents Copy raw contents
Copy raw contents
Copy raw contents
Лекция 8. Ввод-вывод в файлы. Конструкция with
Значки, используемые в тексте
- — отмечает, что высказывание не совсем верно, но будет уточнено позднее.
- ⭐ — выделяет определение нового понятия.
- ❗ — привлекает внимание к высказыванию.
- ☝️ — указывает на небольшое отступление от темы или уточнение.
- — индикатор традиций и договорённостей.
- ⚠️ — требуется осторожность: возможно, сложное высказывание.
Повторение терминов из седьмой лекции
- Конструкция try-except-else — синтаскическая конструкция (сложное утверждение), предназначенная для обработки исключений из блока try в блоках except и выполнения блока else в случае отсутствия ошибок.
- Утверждение raise — утверждение, дающее возможность непосредственно вызвать исключение в коде.
Что такое файл? С точки зрения Python, это объект файловой системы, поддерживающий потоковое чтение и запись.
Для того, чтобы начать работу с файлом (чтение или запись), необходимо открыть файл, с указанием вида работы.
Файл обычно идентифицируется именем, и Python также использует имя файла для его открытия, которое осуществляется встроенной функцией open() :
Функция open() принимает как минимум 1 аргумент — имя файла — и возвращает объект типа file (также встроенный в Python тип), с которым далее и ведётся работа. Вторым аргументом функции указывается способ работы, то есть чтение или запись; по умолчанию, файл открывается на чтение.
У объекта файла есть набор атрибутов и методов, которые в дальнейшем используются для работы с файлом.
Имя файла, связанного с объектом, доступно через атрибут file.name :
При отсутствии такого файла или невозможности открыть его (например, нет разрешений, либо файл является каталогом) возникнет исключение IOError .
Чтобы прочитать содержимое файла, используется метод file.read() . Он возвращает Python-строку ( str ) состоящую из всего содержимого файла, либо если передать ему 1 аргумент — целое число N, то строка будет состоять из первых N байт файла (либо файла целиком, если его размер меньше N байт).
Можно написать программу из 2 строк, которая выведет собственный код, для этого достаточно сохранить её в файл например program1.py и написать:
Указатель позиции в файле
Если вызвать метод file.read() без аргументов более одного раза, то он вернёт пустую строку:
Объяснение этому таково. Файл можно представить как упорядоченную последовательность байт, каждый из которых имеет индекс, начиная с 0 (первый байт) и до «размер файла — 1». При чтении данных из файла, каждый байт условно по очереди передаётся в строку-результат, и индекс (указатель на текущий байт) увеличивается. По окончании чтения, индекс остаётся в том же месте, и следующее чтение начнётся с этого индекса. Если мы уже прочитали весь файл, то логично, что данных после текущего указателя уже нет.
Метод file.read() не только читает данные из файла, но и увеличивает указатель на кол-во прочитанных байт. Если в цикле читать из файла по одному байту, то каждый раз в результате чтения будет следующий байт, до тех пор, пока мы не достигнем конца файла.
Текстовые и бинарные файлы
Во многих системах файлы бывают двух «разновидностей»: текстовые и двоичные (бинарные). В общем любой файл можно считать бинарным, особенно если нам не требуется работать с файлом по частям. Если мы считываем весь файл в строку с помощью метода file.read() , то далее мы можем работать со строкой, полностью игнорируя вид файла.
Главное отличие этих видов в семантике доступа: для текстовых файлов имеет смысл построчный доступ, для бинарных — посимвольный или буферизованный.
С точки зрения пользователя, вид файла не всегда имеет значение, скажем, файл с данными xml или json по содержанию является текстовым, но едва ли имеет смысл обрабатывать его построчно, так как данные представляют собой единую структуру. В то же время файл типа doc для пользователя представляет двоичную кодировку текста.
Работа с текстовыми файлами
Типичным текстовым файлом является файл программы на Python. Для построчного чтения текстовых файлов существует метод file.readline() , который читает строку из файла и увеличивает указатель на длину прочитанной строки. При этом конец строки определяется настройками текущей ОС: для Linux концом строки служит символ перевода строки «\n» (или «\x0a» ), для Windows — последовательность «\r\n» (или «\x0d\x0a» ).
Этот метод удобно использовать в цикле while , опять же проверяя, что считанная строка не пустая. Также в этом методе можно задавать максимальную длину считываемой строки.
Для большего удобства построчного чтения файлов целиком, в цикле for мы можем использовать метод file.readlines() :
Или даже ещё проще:
Объект типа файл является итерируемым, как списки и строки, и итерируется по строкам, содержащимся в файле.
Работа с бинарными файлами
Для итеративной (поблочной) работы с бинарными файлами используется метод file.read(N) , где N — размер считываемого блока. Проверять, что достигнут конец файла, можно, сравнивая длину результата с N, либо также считывать до получения пустой строки.
У бинарных файлов есть ещё одно отличие: мы можем узнать, где сейчас указатель, и передвинуть указатель вручную на нужное место. (То есть, мы можем это делать и в текстовых файлах, но там это бессмысленно.) Для этого предназначены два соответствующих метода: file.tell() и file.seek() .
Первый возвращает индекс байта, на котором сейчас указатель; второй — принимает число-индекс в качестве аргумента и устанавливает указатель на этот индекс.
Таким образом, мы в теории сможем при достижении конца файла вернуть указатель на начало и прочитать содержимое заново. Впрочем, на практике это крайне редко используется.
Для разрешения записи в файл, как мы уже упомянули выше, необходимо сообщить функции open() , что мы открываем файл на запись. Режим работы с файлом передаётся вторым аргументом функции open() и представляет собой строку.
Запись может быть двух видов: перезапись (создание файла, если его ещё нет, либо пересоздание файла, если он уже есть) и дозапись (добавление в конец файла, если он есть, либо ошибка IOError в случае отсутствия).
Режим записи обозначается строкой «w» , режим добавления — строкой «a» .
Далее, собственно писать в файл можно исользуя метод file.write() , который принимает параметр — Python-строку с содержимым для записи. При записи, как и при чтении, указатель позиции в файле увеличивается на количество записанных байт.
Однако если просто записать в открытый файл, записанные данные не сохранятся. Для сохранения данных необходимо закрыть файл, это делается методом file.close() .
Примечание: файлы сами закрываются при выходе из программы, но крайне рекомендуется закрывать их вручную во избежание ошибок.
Смешанные режимы открытия файла
Возможно также открыть файл в режиме, совмещающем чтение и запись. Существует три таких режима:
- чтение с возможностью записи, режим «r+»
- перезапись с возможностью чтения, режим «w+»
- дозапись с возможностью чтения, режим «a+»
Они в целом соответствуют своим «основным» режимам.
Некоторые синтаксические конструкции, облегчающие работу с файлами
Представим себе ситуацию, что мы обрабатываем файл построчно и ищем какую-то строку, после которой дальнейшая обработка уже не имеет смысла. Используя цикл for , нам бы пришлось создавать переменную-флаг и «вхолостую» пробегать остаток файла, проверяя этот флаг в каждой итерации.
К счастью, в Python можно обойтись куда более простой конструкцией.
Утверждение break даёт команду немедленно выйти из цикла к следующему за ним утверждению, полностью пропустив оставшиеся итерации и также все утверждения, идущие в блоке кода цикла после break .
В данном случае будет выводиться на экран каждая строка до строки, содержащей «end», не включая её, потому что цикл закончится до вывода её на экран.
Утверждение break можно использовать не только в обработке файлов, и не только в цикле for : циклы while также поддерживают его. Но в любом другом блоке кода, который не относится к циклам, использование break является синтаксической ошибкой.
Утверждение continue является дополнением break : оно пропускает все следующие за ним утверждения в блоке кода цикла и переходит к следующей его итерации. В случае с циклом for это означает — к обработке следующего элемента (если он есть), в случае while — к следующей проверке условия.
Его удобно использовать, если нам нужно, наоборот, начать обработку файла с какой-то строки файла или пропустить обработку строки.
Этот код будет пропускать все строки файла до строки, содержащей «start», начиная с неё, он начнёт выводить все те строки, которые не содержат «skip».
Объект файла, будучи итерируемым объектом (типа контейнера) является ещё и так называемым контекстным менеджером.
Контекстный менеджер умеет автоматически выполнять некторые действия по окончанию выполнения определённого контекста, который задаётся конструкцией with :
БЛОК_КОДА в данном случае и является контекстом. Независимо от того, произошли ли ошибки в БЛОКе_КОДА, контекстный менеджер всегда выполнит завершающие действия, а именно для файлов — их закрытие.
Возьмём пример, использованный выше:
Его можно переписать так:
И файл автоматически будет закрыт по окончанию блока кода в with .
Записать в новый текстовый файл числа от 1 до 10 по одному в строке.
- в файл можно записать только строковые данные.
- В конец записываемой строки необходимо добавлять символы перевода строки, для Windows это последовательность «\r\n» .
Прочитать из записанного файла числа от 3 до 7 включительно, используя break и continue . В результате должен получиться список из 5 чисел.
Работа с файлами
Для открытия файлов в python используется функция open :
| Режим | Обозначение |
|---|---|
| ‘r’ | открытие на чтение (является значением по умолчанию). |
| ‘w’ | открытие на запись, содержимое файла удаляется, если файла не существует, создается новый. |
| ‘x’ | открытие на запись, если файла не существует, иначе исключение. |
| ‘a’ | открытие на дозапись, информация добавляется в конец файла. |
| ‘b’ | открытие в двоичном режиме. |
| ‘t’ | открытие в текстовом режиме (является значением по умолчанию). |
| ‘+’ | открытие на чтение и запись |
Таким образом, если мы хотим открыть файл в двоичном формате для записи, надо использовать режим “wb”, если мы хотим дописать содержимое в конец файла в текстовом формате, то — “a” или “at”, “r+b” — открыть двоичный файл на чтение и запись.
Обычно, файлы, в которых содержится текст, например, файлы txt , код вашей программы, файлы формата csv , открываются в текстовом формате, а файлы, которые нельзя проинтерпретировать как текст — в бинарном (например, картинки, музыку). Иногда файлы с текстом открывают в бинарном режиме, для более явного управления всеми спецсимволами (например табуляция ↹).
При открытии файла в текстовом режиме, также можно указать подходящую кодировку. Например, если в вашем файле содержится текст на русском в utf8, откройте его в этой кодировке:
Как только файл был открыт и у вас появился файловый объект, вы можете получить следующую информацию о нем:
| Атрибут | Значение |
|---|---|
| file.closed | Возвращает True если файл был закрыт. |
| file.mode | Возвращает режим доступа, с которым был открыт файл. |
| file.name | Возвращает имя файла. |
У получаемого объекта есть несколько полезных методов, рассмотрим их.
метод read ( n ) позволяет прочитать следующие n символов файла. Замечу, что можно представить, что в нашем объекте файла есть указатель на текущую читаемую позицию. При открытии файла, она ставится в самое начало. По мере чтения, этот указатель сдвигается. Таким образом, если выполнять read ( n ) несколько раз подряд, мы будем получать не первые n символов, а каждый раз новые, n символов.
Если n явно не указать, то считается весь файл целиком (указатель окажется в самом конце файла). Для использования метода read, файл должен быть открыт в режиме для чтения Примечание: чтобы узнать текущее положение указателя внутри файла, можно воспользоваться методом tell () , а чтобы установить указатель в нужное положение pos , используется метод seek ( pos )
если файл был открыт в режиме для записи, можно воспользоваться методом python: write(buffer) — записывает содержимое буфера в файл. Работа указателя при записи аналогична — он указывает на текущее обрабатываемое место.
Примечание: при записи содержимого в файл, не гарантируется, что все запишется в файл здесь и сейчас, сразу после выполнения команды. Записываемая информация буферизуется (накапливается) и записывается при накоплении некоторого критического количества. Двоичные файлы буферизуются кусками фиксированного размера. Этот размер определяется эвристикой, пытающейся определить размер блока устройства, на котором находится файл, в случае неудачи использует io.DEFAULT_BUFFER_SIZE. Для многих систем буфер равен 4096 или 8192 байт. Содержимое принудительно записывется в файл при его закрытии. Также для принудительной записи в файл можно воспользоваться методом flush() — он просто записывает содержимое текущего буффера в файл здесь и сейчас.
Следует сказать, что открытый в любом режиме файл после его использования нужно обязательно закрывать. Делается это методом close(). Посе его выполнения работа с файлом будет корректно завершена, но с нашим объектом файла работать уже тоже будет нельзя — при необходимости повторной работы с файлом нужно снова его открывать при помощи open.
Но вдруг в процессе выполнения нашей программы произройдет критическая ошибка и программа завершит свое выполнение, а мы, например, записывали в файл какую-то информацию? Верно, вполне возможно, что последняя добавленная информация в файл так и не запишется. Чтобы избежать такой ситуации, ну и чтобы просто не забывать вовремя вызывать close() используется конструкция with:
Через конструкцию with можно открывать сразу несколько файлов:
- Чтобы считать из файла целую строку, используется метод readline(max_len). Если указать параметр max_len, то будут считаны максимум max_len символов
На самом деле у нашего объекта файла есть итератор, поэтому перебирать строки внутри файла можно с его помощью:
Такой способ чтения наиболее удобен для построчного чтения
Работа с файловой системой
Взаимодействие с файлами не ограничивается только самими файлами, нам часто приходится работать и с папками. Главными героями этого раздела будут библиотеки os и os.path. Они связаны с операционной системой компьютера и позволяют взаимодейстовать с файловой системой.
Все папки директории
os.listdir(dir) перечисялет файлы и папки в указанной директории dir. Если вызвать эту функцию без аргументов, она вернет файлы и папки текущей рабочей директории.
Текущая папка
Относительные пути строятся относительно текущей папки. Чтобы получить абсолютный путь файла из относительного, используется функция os.path.abspath(file_path). Чтобы узнать, какая папка является текущей, можно вызвать функцию os.getcwd(). Для смены текущей папки используется os.chdir(new_dir).
Проверка существования файла или папки и определение, является ли имя файлом или папкой
os.path.exists(file_name) проверяет, существует ли указанный файл (или директория) file_name.
Чтобы проверить, является ли данное имя name файлом или папкой, можно воспользоваться функциями os.isdir(name) или os.isfile(name), которые возвращают True или False.
Рекурсивный обход папок
Одной из самых интересных и мощных функций является функция os.walk(dir) — она позволяет рекурсивно пройтись по всем папкам, подпапкам, их подпапкам и так далее. На самом деле она возвращает генератор (последовательность элементов). Каждый элемент представляеьт собой кортеж из 3х элементов. Первый элемнт — строковое представление директории текущей директории, которую просматривает функция. Вторым элементом — список всех подпапок данной директории, а третьим — список всех файлов этой директории.
Копирование файлов
Копировать файлы можно при помощи функции copy из модуля shutil
Копировать папки можно с помощью copytree из того же модуля:
Многие другие функции для работы с файлами и папками вы сможете найти в модулях os и shutil. Теперь вы знаете, где искать нужный функционал 😉
Упражнение 3: Вам дана в архиве файловая структура, состоящая из директорий и файлов.
Вам необходимо распаковать этот архив (средствами языка python), и затем найти в данной в файловой структуре все директории, в которых есть хотя бы один файл с расширением “.py”.
Ответом на данную задачу будет являться файл со списком таких директорий, отсортированных в лексикографическом порядке.
Распространенные форматы текстовых данных
csv является табличным форматом. В нем содержатся значения разделенные запятой (Comma-Separated Values). Например,
Для работы с csv файлами можно воспользоваться библиотекой csv:
Это универсальные структуры данных. Почти все современные языки программирования поддерживают их в какой-либо форме. Логично предположить, что формат данных, независимый от языка программирования, должен быть основан на этих структурах.
Объекты в формате SJON хранятся как словари в Python, но с некоторыми деталями: во первых, ключом в json-объекте может быть только строка, значения True и False пишутся с маленькой буквы, значению None соответствует значение null, строки хранятся только внутри двойных кавычек.
Для удобной работы с json файлами в языке python можно использовать библиотеку json
Для получения объекта python на основе его срокового представления можно воспользоваться функцией json.loads или json.load для считывания из файла:
При записи-считывнии объектов из формата json кортежи превращаются в списки # Исключения (материал ниже взят с сайта https://pythonworld.ru/tipy-dannyx-v-python/isklyucheniya-v-python-konstrukciya-try-except-dlya-obrabotki-isklyuchenij.html )
Исключения (exceptions) — ещё один тип данных в python. Исключения необходимы для того, чтобы сообщать программисту об ошибках.
Самый простейший пример исключения — деление на ноль:
Разберём это сообщение подробнее: интерпретатор нам сообщает о том, что он поймал исключение и напечатал информацию (Traceback (most recent call last)).
Далее имя файла (File ""). Имя пустое, потому что мы находимся в интерактивном режиме, строка в файле (line 1);
Выражение, в котором произошла ошибка (100 / 0).
Название исключения (ZeroDivisionError) и краткое описание исключения (division by zero).
Разумеется, возможны и другие исключения:
В этих двух примерах генерируются исключения TypeError и ValueError соответственно. Подсказки дают нам полную информацию о том, где порождено исключение, и с чем оно связано.
Рассмотрим иерархию встроенных в python исключений, хотя иногда вам могут встретиться и другие, так как программисты могут создавать собственные исключения. Данный список актуален для python 3.3, в более ранних версиях есть незначительные изменения.
- BaseException — базовое исключение, от которого берут начало все остальные.
- SystemExit — исключение, порождаемое функцией sys.exit при выходе из программы.
- KeyboardInterrupt — порождается при прерывании программы пользователем (обычно сочетанием клавиш Ctrl+C).
- GeneratorExit — порождается при вызове метода close объекта generator.
- Exception — а вот тут уже заканчиваются полностью системные исключения (которые лучше не трогать) и начинаются обыкновенные, с которыми можно работать.
- StopIteration — порождается встроенной функцией next, если в итераторе больше нет элементов.
- ArithmeticError — арифметическая ошибка.
- FloatingPointError — порождается при неудачном выполнении операции с плавающей запятой. На практике встречается нечасто.
- OverflowError — возникает, когда результат арифметической операции слишком велик для представления. Не появляется при обычной работе с целыми числами (так как python поддерживает длинные числа), но может возникать в некоторых других случаях.
- ZeroDivisionError — деление на ноль.
- IndexError — индекс не входит в диапазон элементов.
- KeyError — несуществующий ключ (в словаре, множестве или другом объекте).
- UnboundLocalError — сделана ссылка на локальную переменную в функции, но переменная не определена ранее.
- BlockingIOError
- ChildProcessError — неудача при операции с дочерним процессом.
- ConnectionError — базовый класс для исключений, связанных с подключениями.
- BrokenPipeError
- ConnectionAbortedError
- ConnectionRefusedError
- ConnectionResetError
- IndentationError — неправильные отступы.
- TabError — смешивание в отступах табуляции и пробелов.
- UnicodeEncodeError — исключение, связанное с кодированием unicode.
- UnicodeDecodeError — исключение, связанное с декодированием unicode.
- UnicodeTranslateError — исключение, связанное с переводом unicode.
Теперь, зная, когда и при каких обстоятельствах могут возникнуть исключения, мы можем их обрабатывать. Для обработки исключений используется конструкция try — except.
Первый пример применения этой конструкции:
В блоке try мы выполняем инструкцию, которая может породить исключение, а в блоке except мы перехватываем их. При этом перехватываются как само исключение, так и его потомки. Например, перехватывая ArithmeticError, мы также перехватываем FloatingPointError, OverflowError и ZeroDivisionError.
Также возможна инструкция except без аргументов, которая перехватывает вообще всё (и прерывание с клавиатуры, и системный выход и т. д.). Поэтому в такой форме инструкция except практически не используется, а используется except Exception. Однако чаще всего перехватывают исключения по одному, для упрощения отладки (вдруг вы ещё другую ошибку сделаете, а except её перехватит).
Ещё две инструкции, относящиеся к нашей проблеме, это finally и else. Finally выполняет блок инструкций в любом случае, было ли исключение, или нет (применима, когда нужно непременно что-то сделать, к примеру, закрыть файл). Инструкция else выполняется в том случае, если исключения не было.