Чтение и запись файлов с помощью Python, этого достаточно

Python

Эта статья является переводом, ссылка на оригиналread-write-files-pythonМой блог:Дзен-мастер программирования

Наиболее распространенные задачи, выполняемые с помощью Python, — это чтение и запись файлов. Будь то запись простых текстовых файлов, чтение сложных журналов сервера или анализ необработанных байтовых данных. Во всех этих случаях требуется чтение или запись файла.

В этом уроке вы узнаете:

  • Состав файла и почему это важно в Python
  • Основы чтения и записи файлов в Python
  • Некоторые сценарии чтения и записи файлов с помощью Python

Это руководство в первую очередь предназначено для начинающих и продолжающих разработчиков Python, но вот несколько советов, которыми могут воспользоваться и более продвинутые программисты.

Что такое файл?

Прежде чем мы начнем рассматривать, как работать с файлами в Python, важно понять, что такое файлы и некоторые аспекты того, как современные операционные системы обрабатывают их.

По сути, файлдля хранения данныхНепрерывный набор байтов. Эти данные организованы в определенном формате и могут быть как простыми, как текстовый файл, так и сложными, как исполняемый файл программы. Наконец, эти байтовые файлы преобразуются в двоичные файлы.1,0для облегчения работы компьютера.

Файл в большинстве современных файловых систем состоит из трех основных частей:

  1. **Заголовок:**Метаданные о содержимом файла (имя файла, размер, тип и т. д.)
  2. **Данные:**Содержимое файла, написанное создателем или редактором.
  3. **Конец файла (EOF): **Специальный символ, указывающий на конец файла

FileForma

Содержание представления данных зависит от используемой спецификации формата, обычно представляемой расширением. Например, расширение.gifдокументов, наиболее вероятно совпадающихФормат обмена графикойСпецификация. Их сотни (если не тысячи)расширение файла. В этом уроке вы будете иметь дело только с.txtили.csvрасширение файла.

Путь файла

При доступе к файлу в операционной системе требуется путь к файлу. Путь к файлу — это строка, представляющая расположение файла. Он разделен на три основные части:

  1. **Путь к папке:** расположение папки в файловой системе, последующие папки обозначаются косой чертой./(Unix) или обратная косая черта\(Windows) Разделение
  2. имя файла: файлнастоящее имя
  3. **Расширение:** В конец пути к файлу добавляется точка (.) Для типа файла

Вот простой пример. Предположим, у вас есть файл, расположенный в файловой структуре, подобной этой:

/
│
├── path/
|   │
│   ├── to/
│   │   └── cats.gif
│   │
│   └── dog_breeds.txt
|
└── animals.csv

Предположим, вы хотите получить доступ кcats.gifфайл, и ваше текущее местоположение находится в той же папке, что иpathтот же уровень. Чтобы получить доступ к этому файлу, вам нужно просмотретьpathпапку, а затем просмотретьtoпапку и, наконец, вcats.gifдокумент. Путь к папкеpath/to/. имя файлаcats. расширение файла.gif. Итак, полный путьpath/to/cats.gif.

Теперь предположим, что ваше текущее местоположение или текущий рабочий каталог (cwd) находится в нижней части структуры папок нашего примера.toпапка. На файлы можно просто ссылаться по их имени и расширениюcats.gif, вместо того, чтобы цитироватьcats.gifПолный маршрутpath/to/cats.gif.

/
│
├── path/
|   │
|   ├── to/  ← Your current working directory (cwd) is here
|   │   └── cats.gif  ← Accessing this file
|   │
|   └── dog_breeds.txt
|
└── animals.csv

но дляdog_breeds.txtКак получить к нему доступ? Как бы вы получили доступ, не используя полный путь? Вы можете использовать специальный символ двойной точки (..) для перемещения вперед на один каталог. Это означает, что вtoиспользование каталога../dog_breeds.txtЦитироватьdog_breeds.txtдокумент.

/
│
├── path/  ← Referencing this parent folder
|   │
|   ├── to/  ← Current working directory (cwd)
|   │   └── cats.gif
|   │
|   └── dog_breeds.txt  ← Accessing this file
|
└── animals.csv

двойная точка (..) могут быть объединены для обхода нескольких каталогов перед текущим каталогом. Например, вtoпапка для доступаanimals.csv, вы будете использовать../../animals.csv.

окончание строки

Проблема, с которой часто приходится сталкиваться при работе с файловыми данными, — это представление символов новой строки или окончания строки. Окончания строк возникли в эпоху азбуки Морзе,Использование определенного символа используется для обозначения конца передачи или конца строки..

Позже Международная организация по стандартизации (ISO) и Американская ассоциация стандартов (ASA)к телетайпустандартизированный. Стандарт ASA указывает, что возврат каретки (последовательность) должен использоваться в конце строки.CRили\r)иновая линия (LFили\n)персонаж(CR+LFили\r\n). Однако стандарт ISO позволяетCR+LFхарактер или толькоLFперсонаж.

Использование WindowsCR+LFперсонажозначает новую строку, тогда как Unix и более новые версии Mac используют толькоLFперсонаж. Это может привести к некоторым сложностям при работе с файлами, происходящими из разных операционных систем. Вот простой пример. Предположим, мы исследуем файл, созданный в системе Windows.dog_breeds.txt:

Pug\r\n
Jack Russel Terrier\r\n
English Springer Spaniel\r\n
German Shepherd\r\n
Staffordshire Bull Terrier\r\n
Cavalier King Charles Spaniel\r\n
Golden Retriever\r\n
West Highland White Terrier\r\n
Boxer\r\n
Border Terrier\r\n

Один и тот же вывод будет интерпретироваться по-разному на устройствах Unix:

Pug\r
\n
Jack Russel Terrier\r
\n
English Springer Spaniel\r
\n
German Shepherd\r
\n
Staffordshire Bull Terrier\r
\n
Cavalier King Charles Spaniel\r
\n
Golden Retriever\r
\n
West Highland White Terrier\r
\n
Boxer\r
\n
Border Terrier\r
\n

Это может привести к повторяющимся проблемам для каждой строки, и вы можете рассмотреть такие случаи.

Кодировка символов

Другая распространенная проблема, с которой вы можете столкнуться, — это кодирование байтовых данных. Кодирование — это преобразование байтовых данных в удобочитаемые символы. Обычно это делается путем указания формата кодировки. Две наиболее распространенные кодировки:ASCIIиUNICODEФормат.ASCII может хранить только 128 символовЮникод может содержать до 1 114 112 символов..

ASCII на самом деле является подмножеством Unicode (UTF-8), что означает, что ASCII и Unicode имеют одни и те же числовые значения символов. Важно отметить, что синтаксический анализ файла с неправильной кодировкой символов может привести к сбоям и ошибкам преобразования символов. Например, если файл был создан в кодировке UTF-8, а вы пытаетесь проанализировать его в кодировке ASCII, возникнет ошибка, если символы превышают эти 128 значений.


Открывать и закрывать файлы в Python

Когда вы хотите использовать файл, первое, что вы делаете, это открываете его. Эта операция выполняется путем вызоваopen()Встроенные функции сделаны.open()Есть один обязательный параметр — путь к файлу.open()Возврат есть, именно этот файлфайловый объект:

file = open('dog_breeds.txt')

После открытия файла следующее, чему нужно научиться, это как его закрыть.

**ВНИМАНИЕ:** ВЫ ДОЛЖНЫвсегдаНе забудьте правильно закрыть открытые файлы.

Важно помнить, что закрытие файла является вашей ответственностью. В большинстве случаев файл в конечном итоге будет закрыт после завершения работы приложения или сценария. Однако нет никакой гарантии, что произойдет на самом деле. Это может привести к нежелательному поведению, включая утечку ресурсов. Это также является передовой практикой в ​​Python (Pythonic), чтобы гарантировать, что ваш код ведет себя четко определенным образом и уменьшает любое нежелательное поведение.

При работе с файлами есть два способа обеспечить правильное закрытие файла, даже если вы столкнулись с ошибками. Первый способ закрыть файл — использоватьtry-finallyкусок:

reader = open('dog_breeds.txt')
try:
    # Further file processing goes here
finally:
    reader.close()

Если вы не знакомы сtry-finallyзаблокировать контент, см.Исключения Python: введение.

Второй способ закрыть файл — использовать следующийwithЗаявление:

with open('dog_breeds.txt') as reader:
    # Further file processing goes here

использоватьwithЗаявление, когда-то оставленноеwithблокировать или даже в случае ошибки система автоматически закроет файл. Я настоятельно рекомендую вам использовать как можно большеwithоператор, так как он делает код чище и упрощает обработку любых непредвиденных ошибок.

Скорее всего, вы также захотите использовать второй позиционный параметрmode. Этот параметр представляет собой строку, содержащую несколько символов, чтобы указать, как вы хотите открыть файл. По умолчанию и наиболее распространены'r', что означает открыть файл как текстовый файл в режиме только для чтения:

with open('dog_breeds.txt', 'r') as reader:
    # Further file processing goes here

Посмотреть другие режимыонлайн-документация, но наиболее распространены следующие шаблоны:

модель значение
'r' Режим только для чтения включен (по умолчанию)
'ж' Открыть в режиме записи, перезапишет файл
'rb'или'wb' Открыть в двоичном режиме (чтение/запись с байтовыми данными)

Вернемся назад и поговорим о файловых объектах. Файловый объект:

"Файловый API (с использованиемread()or write()и т. д.) объекты, открытые для базового ресурса. "(источник)

Существует три различных типа файловых объектов:

  • текстовый файл
  • буферизованный двоичный файл
  • необработанные двоичные файлы

для каждого из этих типов файлов вioопределяется в модуле. Здесь кратко описаны три типа.

текстовый файл

Текстовые файлы являются наиболее распространенными файлами, с которыми вы столкнетесь. Вот несколько примеров того, как открыть эти файлы:

open('abc.txt')

open('abc.txt', 'r')

open('abc.txt', 'w')

Для этого типа файлаopen()вернетTextIOWrapperфайловый объект:

>>> file = open('dog_breeds.txt')
>>> type(file)
<class '_io.TextIOWrapper'>

Этоopen()Файловый объект, возвращаемый по умолчанию.

Буферизованный двоичный тип файла

Тип буферизованного двоичного файла используется для чтения и записи двоичных файлов. Вот несколько примеров того, как открыть эти файлы:

open('abc.txt', 'rb')

open('abc.txt', 'wb')

Для этого типа файлаopen()вернетBufferedReaderилиBufferedWriterфайловый объект:

>>> file  =  open ('dog_breeds.txt' , 'rb' )
>>> type (file )
<class'_io.BufferedReader'> 
>>> file  =  open ('dog_breeds.txt' , 'wb' )
> >> type (file )
<class'_io.BufferedWriter'>

исходный тип файла

Исходный тип файла:

"Обычно используется в качестве низкоуровневого строительного блока для двоичных и текстовых потоков."(источник)

Поэтому его обычно не используют.

Вот пример того, как открыть эти файлы:

open('abc.txt', 'rb', buffering=0)

Для этого типа файлаopen()вернетFileIOфайловый объект:

>>> file = open('dog_breeds.txt', 'rb', buffering=0)
>>> type(file)
<class '_io.FileIO'>

Чтение и запись открытых файлов

После открытия файла вам нужно будет прочитать или записать в файл. Во-первых, давайте прочитаем файл. Для файлового объекта могут быть вызваны различные методы:

метод описывать
.read(size=-1) Это будет основано наsizeКоличество байтов, прочитанных из файла. если аргументы не переданы илиNoneили-1, то читается весь файл.
.readline(size=-1) Это будет читать больше всего из строкиsizeколичество символов. до конца строки, затем на следующую строку. если аргументы не переданы илиNoneили-1, считывается вся строка (или оставшаяся часть строки).

используйте тот, который использовался вышеdog_breeds.txtфайл, давайте рассмотрим несколько примеров использования этих методов. Вот как использовать.read()Пример команды, чтобы открыть и прочитать весь файл:

>>> with open('dog_breeds.txt', 'r') as reader:
>>>     # Read & print the entire file
>>>     print(reader.read())
Pug
Jack Russel Terrier
English Springer Spaniel
German Shepherd
Staffordshire Bull Terrier
Cavalier King Charles Spaniel
Golden Retriever
West Highland White Terrier
Boxer
Border Terrier

Вот как использовать.readline()Пример чтения 5 байт за раз в одной строке:

>>> with open('dog_breeds.txt', 'r') as reader:
>>>     # Read & print the first 5 characters of the line 5 times
>>>     print(reader.readline(5))
>>>     # Notice that line is greater than the 5 chars and continues
>>>     # down the line, reading 5 chars each time until the end of the
>>>     # line and then "wraps" around
>>>     print(reader.readline(5))
>>>     print(reader.readline(5))
>>>     print(reader.readline(5))
>>>     print(reader.readline(5))
Pug

Jack 
Russe
l Ter
rier

Примечание переводчика: первый вызов reader.readline(5) на самом деле печатает Pug\r\n, так что вы можете видеть, что в выводе есть новая строка

Используется следующее.readlines()Пример чтения всего файла в виде списка:

>>> f = open('dog_breeds.txt')
>>> f.readlines()  # Returns a list object
['Pug\n', 'Jack Russel Terrier\n', 'English Springer Spaniel\n', 'German Shepherd\n', 'Staffordshire Bull Terrier\n', 'Cavalier King Charles Spaniel\n', 'Golden Retriever\n', 'West Highland White Terrier\n', 'Boxer\n', 'Border Terrier\n']

Приведенный выше пример также можно выполнить с помощьюlist()Это делается путем создания списка из файлового объекта:

>>> f = open('dog_breeds.txt')
>>> list(f)
['Pug\n', 'Jack Russel Terrier\n', 'English Springer Spaniel\n', 'German Shepherd\n', 'Staffordshire Bull Terrier\n', 'Cavalier King Charles Spaniel\n', 'Golden Retriever\n', 'West Highland White Terrier\n', 'Boxer\n', 'Border Terrier\n']

перебирать каждую строку в файле

Обычная вещь при чтении файлов - перебирать каждую строку. Вот как использовать.readline()Пример выполнения этой итерации:

>>> with open('dog_breeds.txt', 'r') as reader:
>>>     # Read and print the entire file line by line
>>>     line = reader.readline()
>>>     while line != '':  # The EOF char is an empty string
>>>         print(line, end='')
>>>         line = reader.readline()
Pug
Jack Russel Terrier
English Springer Spaniel
German Shepherd
Staffordshire Bull Terrier
Cavalier King Charles Spaniel
Golden Retriever
West Highland White Terrier
Boxer
Border Terrier

Другой способ перебрать каждую строку в файле — использовать.readlines()файловый объект. пожалуйста, помните,.readlines()Возвращает список, в котором каждый элемент списка представляет строку в файле:

>>> with open('dog_breeds.txt', 'r') as reader:
>>>     for line in reader.readlines():
>>>         print(line, end='')
Pug
Jack Russell Terrier
English Springer Spaniel
German Shepherd
Staffordshire Bull Terrier
Cavalier King Charles Spaniel
Golden Retriever
West Highland White Terrier
Boxer
Border Terrier

Однако приведенный выше пример можно еще больше упростить, перебирая сам файловый объект:

>>> with open('dog_breeds.txt', 'r') as reader:
>>>     # Read and print the entire file line by line
>>>     for line in reader:
>>>         print(line, end='')
Pug
Jack Russel Terrier
English Springer Spaniel
German Shepherd
Staffordshire Bull Terrier
Cavalier King Charles Spaniel
Golden Retriever
West Highland White Terrier
Boxer
Border Terrier

Последний метод больше похож на Python и может быть быстрее и эффективнее. Поэтому рекомендуется использовать его вместо этого.

**ПРИМЕЧАНИЕ.** Некоторые из приведенных выше примеров содержатprint('some text', end=''). Этотend=''заключается в том, чтобы предотвратить добавление Python дополнительных строк новой строки к печатаемому тексту и печатать только то, что читается из файла.

Теперь давайте копаться в файле. Как и при чтении файлов, у файлового объекта есть несколько методов, которые можно использовать для записи в файлы:

метод описывать
.write(string) Записать строку в файл.
.writelines(seq) Запишите последовательность в файл. К каждому элементу последовательности не добавляется конечный символ. Вы можете добавить соответствующие завершающие символы.

Используется следующее.write()Простой пример и.writelines():

with open('dog_breeds.txt', 'r') as reader:
    # Note: readlines doesn't trim the line endings
    dog_breeds = reader.readlines()

with open('dog_breeds_reversed.txt', 'w') as writer:
    # Alternatively you could use
    # writer.writelines(reversed(dog_breeds))

    # Write the dog breeds to the file in reversed order
    for breed in reversed(dog_breeds):
        writer.write(breed)

использовать байты

Иногда вам может понадобиться использоватьБайтовая строкаОбработать файлы. сквозьmodeдобавить параметр'b'символов для завершения. Все те же методы, которые применяются к файловым объектам. Однако каждый метод ожидает и возвращаетbytesОбъект:

>>> with open(`dog_breeds.txt`, 'rb') as reader:
>>>     print(reader.readline())
b'Pug\n'

использоватьbФлаги для открытия текстовых файлов не так интересны. Предположим, у нас есть джек-рассел-терьер (jack_russell.png) милые картинки:

jack_russell.jpg

Вы можете открыть этот файл в Python и проверить содержимое! так как.pngформат файлаКак определено, заголовок файла составляет 8 байтов следующим образом:

ценность описывать
0x89 «Волшебное» число, указывающее, что этоPNGНачинать
0x50 0x4E 0x47 PNGASCII
0x0D 0x0A Окончания строк в стиле DOS\r\n
0x1A Символ EOF в стиле DOS
0x0A окончание строки в стиле Unix\n

Открыв файл и прочитав байты по отдельности, вы увидите, что это действительно.pngголовной файл:

>>> with open('jack_russell.png', 'rb') as byte_reader:
>>>     print(byte_reader.read(1))
>>>     print(byte_reader.read(3))
>>>     print(byte_reader.read(2))
>>>     print(byte_reader.read(1))
>>>     print(byte_reader.read(1))
b'\x89'
b'PNG'
b'\r\n'
b'\x1a'
b'\n'

Полный пример:dos2unix.py

Давайте подведем итоги и посмотрим полный пример того, как читать и записывать файлы. Ниже приведенdos2unixАналогичный инструмент, который преобразует файл в его окончания строк.\r\nПреобразовать в\n.

Инструмент разделен на три основные части. первыйstr2unix()преобразовать строку из\\r\\nокончания строк преобразуются в\\n. Второйdos2unix()будет содержать\r\nстрока символов, преобразованная в\n.dos2unix()перечислитьstr2unix(). Наконец, есть__main__блок, который будет вызываться только при выполнении файла как скрипта.

"""
A simple script and library to convert files or strings from dos like
line endings with Unix like line endings.
"""

import argparse
import os


def str2unix(input_str: str) -> str:
    r"""\
    Converts the string from \r\n line endings to \n

    Parameters
    ----------
    input_str
        The string whose line endings will be converted

    Returns
    -------
        The converted string
    """
    r_str = input_str.replace('\r\n', '\n')
    return r_str


def dos2unix(source_file: str, dest_file: str):
    """\
    Coverts a file that contains Dos like line endings into Unix like

    Parameters
    ----------
    source_file
        The path to the source file to be converted
    dest_file
        The path to the converted file for output
    """
    # NOTE: Could add file existence checking and file overwriting
    # protection
    with open(source_file, 'r') as reader:
        dos_content = reader.read()

    unix_content = str2unix(dos_content)

    with open(dest_file, 'w') as writer:
        writer.write(unix_content)


if __name__ == "__main__":
    # Create our Argument parser and set its description
    parser = argparse.ArgumentParser(
        description="Script that converts a DOS like file to an Unix like file",
    )

    # Add the arguments:
    #   - source_file: the source file we want to convert
    #   - dest_file: the destination where the output should go

    # Note: the use of the argument type of argparse.FileType could
    # streamline some things
    parser.add_argument(
        'source_file',
        help='The location of the source '
    )

    parser.add_argument(
        '--dest_file',
        help='Location of dest file (default: source_file appended with `_unix`',
        default=None
    )

    # Parse the args (argparse automatically grabs the values from
    # sys.argv)
    args = parser.parse_args()

    s_file = args.source_file
    d_file = args.dest_file

    # If the destination file wasn't passed, then assume we want to
    # create a new file based on the old one
    if d_file is None:
        file_path, file_extension = os.path.splitext(s_file)
        d_file = f'{file_path}_unix{file_extension}'

    dos2unix(s_file, d_file)

Секреты и уловки

Теперь, когда у вас есть основы чтения и записи файлов, вот несколько советов и приемов, которые помогут вам улучшить свои навыки.

__file__

Должен__file__свойства являются модульнымиспециальные свойства, похожий на__name__. это:

"Если загружается из файла, это путь к файлу, в который был загружен модуль" (источник)

Уведомление:__file__возвращениеВзаимноПуть для вызова начального скрипта Python. Если вам нужен полный системный путь, вы можете использоватьos.getcwd()Получить текущий рабочий каталог исполняемого кода.

Это реальный пример. На одной из своих прошлых работ я несколько раз тестировал аппаратные устройства. Каждый тест написан с использованием скрипта Python с именем файла тестового скрипта, используемым в качестве заголовка. Затем эти сценарии будут выполняться и использоваться__file__Специальное свойство выводит свой статус. Вот пример структуры папок:

project/
|
├── tests/
|   ├── test_commanding.py
|   ├── test_power.py
|   ├── test_wireHousing.py
|   └── test_leds.py
|
└── main.py

бегатьmain.pyпроизводит следующее:

>>> python main.py
tests/test_commanding.py Started:
tests/test_commanding.py Passed!
tests/test_power.py Started:
tests/test_power.py Passed!
tests/test_wireHousing.py Started:
tests/test_wireHousing.py Failed!
tests/test_leds.py Started:
tests/test_leds.py Passed!

Добавить содержимое файла

Иногда вы можете захотеть добавить в файл или начать запись в конце существующего файла. Это можно сделать через параметрmodeдобавить в'a'символы для завершения:

with open('dog_breeds.txt', 'a') as a_writer:
    a_writer.write('\nBeagle')

когда правильноdog_breeds.txtПри повторной проверке вы увидите, что начало файла не изменилось,BeagleТеперь добавлено в конец файла:

>>> with open('dog_breeds.txt', 'r') as reader:
>>>     print(reader.read())
Pug
Jack Russel Terrier
English Springer Spaniel
German Shepherd
Staffordshire Bull Terrier
Cavalier King Charles Spaniel
Golden Retriever
West Highland White Terrier
Boxer
Border Terrier
Beagle

Используйте два файла одновременно

Иногда вам может понадобиться прочитать файл и одновременно записать в другой файл. Если вы используете пример, показанный при обучении записи в файл, его можно включить в следующее:

d_path = 'dog_breeds.txt'
d_r_path = 'dog_breeds_reversed.txt'
with open(d_path, 'r') as reader, open(d_r_path, 'w') as writer:
    dog_breeds = reader.readlines()
    writer.writelines(reversed(dog_breeds))

Создайте свой собственный контекстный менеджер

Иногда вам может понадобиться файл объектов в пользовательском классе, чтобы лучше управлять файловым объектом. Когда вы сделаете это, добавьте несколько магических методов, если иное больше не доступно.withЗаявление: добавив__enter__и__exit__, вы создадите то, что называетсяменеджер контекста.

__enter__()перечислитьwithзаявление называется.__exit__()отwithВызывается при выходе из блока операторов.

Вот шаблон, который можно использовать для создания пользовательских классов:

class my_file_reader():
    def __init__(self, file_path):
        self.__path = file_path
        self.__file_object = None

    def __enter__(self):
        self.__file_object = open(self.__path)
        return self

    def __exit__(self, type, val, tb):
        self.__file_object.close()

    # Additional methods implemented below

Теперь, когда у вас есть собственный класс с менеджером контекста, вы можете использовать встроенныйopen()Используйте это так:

with my_file_reader('dog_breeds.txt') as reader:
    # Perform custom class operations
    pass

Это хороший пример. Помните, у нас была очаровательная фигурка Джека Рассела? может быть, вы хотите открыть другие.pngфайл, но не хотите каждый раз анализировать файл заголовка. Вот пример того, как это сделать. В этом примере также используется пользовательский итератор. Если вы не знакомы с ними, пожалуйста, проверьтеИтератор Python:

class PngReader():
    # Every .png file contains this in the header.  Use it to verify
    # the file is indeed a .png.
    _expected_magic = b'\x89PNG\r\n\x1a\n'

    def __init__(self, file_path):
        # Ensure the file has the right extension
        if not file_path.endswith('.png'):
            raise NameError("File must be a '.png' extension")
        self.__path = file_path
        self.__file_object = None

    def __enter__(self):
        self.__file_object = open(self.__path, 'rb')

        magic = self.__file_object.read(8)
        if magic != self._expected_magic:
            raise TypeError("The File is not a properly formatted .png file!")

        return self

    def __exit__(self, type, val, tb):
        self.__file_object.close()

    def __iter__(self):
        # This and __next__() are used to create a custom iterator
        # See https://dbader.org/blog/python-iterators
        return self

    def __next__(self):
        # Read the file in "Chunks"
        # See https://en.wikipedia.org/wiki/Portable_Network_Graphics#%22Chunks%22_within_the_file

        initial_data = self.__file_object.read(4)

        # The file hasn't been opened or reached EOF.  This means we
        # can't go any further so stop the iteration by raising the
        # StopIteration.
        if self.__file_object is None or initial_data == b'':
            raise StopIteration
        else:
            # Each chunk has a len, type, data (based on len) and crc
            # Grab these values and return them as a tuple
            chunk_len = int.from_bytes(initial_data, byteorder='big')
            chunk_type = self.__file_object.read(4)
            chunk_data = self.__file_object.read(chunk_len)
            chunk_crc = self.__file_object.read(4)
            return chunk_len, chunk_type, chunk_data, chunk_crc

теперь вы можете открыть.pngфайлы и правильно анализировать их с помощью пользовательского менеджера контекста:

>>> with PngReader('jack_russell.png') as reader:
>>>     for l, t, d, c in reader:
>>>         print(f"{l:05}, {t}, {c}")
00013, b'IHDR', b'v\x121k'
00001, b'sRGB', b'\xae\xce\x1c\xe9'
00009, b'pHYs', b'(<]\x19'
00345, b'iTXt', b"L\xc2'Y"
16384, b'IDAT', b'i\x99\x0c('
16384, b'IDAT', b'\xb3\xfa\x9a$'
16384, b'IDAT', b'\xff\xbf\xd1\n'
16384, b'IDAT', b'\xc3\x9c\xb1}'
16384, b'IDAT', b'\xe3\x02\xba\x91'
16384, b'IDAT', b'\xa0\xa99='
16384, b'IDAT', b'\xf4\x8b.\x92'
16384, b'IDAT', b'\x17i\xfc\xde'
16384, b'IDAT', b'\x8fb\x0e\xe4'
16384, b'IDAT', b')3={'
01040, b'IDAT', b'\xd6\xb8\xc1\x9f'
00000, b'IEND', b'\xaeB`\x82'

Не изобретайте велосипед

Распространенные ситуации могут возникнуть при работе с файлами. Большинство случаев могут быть обработаны с помощью других модулей. Два распространенных типа файлов, которые вы, возможно, захотите использовать, это.csvи.json.Real PythonНесколько замечательных статей о том, как с ними бороться:

Кроме того, существуют встроенные библиотеки, которые могут вам помочь:

  • wave: Чтение и запись файлов WAV (аудио)
  • aifc: Чтение и запись файлов AIFF и AIFC (аудио)
  • sunau: чтение и запись файлов Sun AU
  • tarfile: чтение и запись tar-архивов
  • zipfile: использовать ZIP-архив
  • configparser: легко создавать и анализировать файлы конфигурации
  • xml.etree.ElementTree: Создание или чтение файлов на основе XML.
  • msilib: Чтение и запись файлов установщика Microsoft.
  • plistlib: Создание и анализ Mac OS X.plistдокумент

Это еще не все. Кроме того, в PyPI доступно множество других сторонних инструментов. Вот некоторые из популярных:

  • PyPDF2: Инструментарий PDF
  • xlwings: чтение и запись файлов Excel.
  • Pillow: Чтение изображений и манипулирование ими

Суммировать

Теперь вы знаете, как использовать файлы обработки Python, включая некоторые передовые технологии. Файлы в Python теперь проще, чем когда-либо. Когда вы начинаете делать это, это полезное чувство.

В этом уроке вы узнали:

  • что такое файл
  • Как правильно открывать и закрывать файлы
  • Как читать и записывать файлы
  • Некоторые продвинутые приемы работы с файлами
  • Некоторые библиотеки используют общие типы файлов

qrcode_for_gh_aeefa52af384_258.jpg

Подпишитесь на официальный аккаунт , чтобы узнать больше иностранных высококачественных технических статей.