Кодировки и работа с файлами

(Если with не было в прошлых лекциях, то тут)

Оператор with

Далее см. contextlib.html

Байтовые структуры

Bytearray нужен не очень часто:

бНОПНЯ

То, что мы в ИТ называем «символами» — соответствие некоторого маркера термину — в действительности суть «знаки». Понятие «символа» слишком многозначно и нередко представляет собой нечто противоположное знаку: символ маркирует целый культурно-ассоциативный корпус, для каждого человека — а тем более в разных культурах — разный.

Как преобразовать из str в bytes и обратно?

Кодировка
соответствие некоторого числа конкретному символу

Кодировки бывают фиксированного размера и многобайтовые.

⇒ Лучше всегда использовать UTF-8. Остальные ещё хуже.

Представление строк внутри Python:

Не всякие кодировки полны:"Вопрос".encode("koi8-r").decode("latin3")

Устарело ли понятие однобайтовой кодировки? Нет! бНОПНЯ живёт и процветает в Windows, например.

Имена Unicode

Прекрасная статья про Unicode

См. модуль unicodedata + спецсимволы \uxxxx и \N{имя}:

   1 >>> "\u2191" + chr(8709), ord("Ы")
   2 ('↑∅', 1067)
   3 >>> "\N{BOX DRAWINGS LIGHT VERTICAL AND LEFT}"
   4 ''
   5 >>> unicodedata.lookup('MIDDLE DOT')
   6 '·'
   7 >>> unicodedata.name("")
   8 'THERE EXISTS'

Просто файлы

В tutorial

Отдельная тема: «файлы в операционной системе» — слишком много и не про язык, не будем туда ходить.

Стандартный ввод-вывод

Как обычно: sys.stdin, sys.stdout и sys.stderr — это файлы стандартного ввода, вывода и вывода ошибок соответственно

Двоичные аналоги — sys.stdin.buffer, sys.stdout.buffer и sys.stderr.buffer

Файловые объекты

Более высокий уровень абстракции — io (в действительности более низкий)

Типизированные файлы

В «просто файлы» записываются только строки или байты. А если надо записать float, причём не в виде строки?

Для начала вопрос: а в виде чего?

Сериализация

Чтение и запись объектов Python

Пример:

   1 >>> import pickle
   2 >>> pickle.dumps(0x14131211)
   3 b'\x80\x04\x95\x06\x00\x00\x00\x00\x00\x00\x00J\x11\x12\x13\x14.'
   4 >>> pickle.dumps(0x14131211)[-5:]
   5 b'\x11\x12\x13\x14.'
   6 >>> du = pickle.dumps(123.123e20)
   7 >>> du
   8 b'\x80\x04\x95\n\x00\x00\x00\x00\x00\x00\x00GD\x84\xdb\x9b\xe5\x05\x1cP.'
   9 >>> ud = pickle.loads(du)
  10 >>> ud
  11 1.23123e+22
  12 >>> F = open("serialized", "bw")
  13 >>> pickle.dump(100500, F)
  14 >>> pickle.dump([1, "WER", None], F)
  15 >>> pickle.dump(b"QWWER", F)
  16 >>> F.close()
  17 >>> F = open("serialized", "br")
  18 >>> pickle.load(F)
  19 100500
  20 >>> pickle.load(F)
  21 [1, 'WER', None]
  22 >>> pickle.load(F)
  23 b'QWWER'
  24 

Сериализация экземпляра класса:

TODO в 3.14 поменяли протокол на 5, надо будет переделать пример

Структуры типа Си

Что мешает записать / считать представление объекта в памяти — это и будет в точности его контент?

struct

Простой пример запаковки произвольных данных:

   1 >>> struct.pack("IhBi", 100500, 32100, 200, -6)
   2 b'\x94\x88\x01\x00d}\xc8\x00\xfa\xff\xff\xff'
   3 

Пример: заголовок PNG (возможно, не успеем)

   1 import struct
   2 import zlib
   3 import sys
   4 
   5 HEADER = "8B"
   6 CHUNK = "!I4s"
   7 CRC = "!I"
   8 IHDR = "!IIBBBBB"
   9 
  10 def readpack(fmt, fle):
  11     return struct.unpack(fmt, fle.read(struct.calcsize(fmt)))
  12 
  13 payload = b''
  14 with open(sys.argv[1], "br") as f:
  15     png = readpack(HEADER, f)
  16     print(*map(hex, png))
  17     while (chunk := readpack(CHUNK, f))[1] != b"IEND":
  18         print(*chunk)
  19         data = f.read(chunk[0])
  20         crc = readpack(CRC, f)
  21         if chunk[1] == b"IHDR":
  22             w, h, bpp, col, comp, filt, i = struct.unpack(IHDR, data)
  23             print(f"{w}×{h}, {bpp=}, {col=}, {comp=}, {filt=}, {i=}")
  24         elif chunk[1] == b"IDAT":
  25             payload += data
  26 
  27 print(len(payload), w, h, w*h)
  28 payload = zlib.decompress(payload)
  29 print(len(payload), w, h, w*h)

TODO Changed in version 3.14: Added support for the 'F' and 'D' formats. — комплексные (для GPU?)

Базы данных и dict-like итерфейс

dbm

Файлы с известной структурой

Д/З

Собственно, задание:

  1. Прощёлкать примеры с файлами в Tutorial, а также примеры по pickle и struct

  2. EJudge: ZipInfo 'Размер архива'

    Написать программу, которой на стандартный ввод подаётся zip-архив в виде шестнадцатеричного дампа (последовательность шестнадцатеричных цифр, возможно, разделённых пробелами и переводами строки), а на выходе она показывает количество и суммарный объём хранящихся в нём файлов, если их распаковать.

    Input:

    504b03040a0000000000d6a07c5100000000000000000000000002001c00
    6f2f5554090003a483c25fab83c25f75780b000104f501000004f5010000
    504b03040a00000000000ea77c5100000000000000000000000004001c00
    6f2f312f55540900034c8fc25f568fc25f75780b000104f501000004f501
    0000504b03040a0000000000d8a07c510000000000000000000000000600
    1c006f2f312f352f5554090003a783c25fab83c25f75780b000104f50100
    0004f5010000504b03040a00000000000da77c5100000000000000000000
    000006001c006f2f312f322f5554090003498fc25f568fc25f75780b0001
    04f501000004f5010000504b03040a00000000000da77c514b8325172100
    0000210000000a001c006f2f312f322f646174655554090003498fc25f56
    8fc25f75780b000104f501000004f5010000d0a1d0b120d0bdd0bed18f20
    32382032303a35363a3235204d534b20323032300a504b03040a00000000
    0066a67c5100000000000000000000000008001c006f2f312f322f332f55
    54090003108ec25f3f8ec25f75780b000104f501000004f5010000504b03
    040a00000000000aa77c51ba7488890b0000000b0000000b001c006f2f31
    2f322f332f63616c5554090003438fc25f568fc25f75780b000104f50100
    0004f5010000323032302d31312d32380a504b03040a0000000000d6a07c
    510000000000000000000000000a001c006f2f312f322f332f342f555409
    0003a483c25fab83c25f75780b000104f501000004f5010000504b03040a
    00000000000ea77c5100000000000000000000000008001c006f2f312f6e
    6f6e6555540900034c8fc25f568fc25f75780b000104f501000004f50100
    00504b01021e030a0000000000d6a07c5100000000000000000000000002
    0018000000000000001000ed41000000006f2f5554050003a483c25f7578
    0b000104f501000004f5010000504b01021e030a00000000000ea77c5100
    0000000000000000000000040018000000000000001000ed413c0000006f
    2f312f55540500034c8fc25f75780b000104f501000004f5010000504b01
    021e030a0000000000d8a07c510000000000000000000000000600180000
    00000000001000ed417a0000006f2f312f352f5554050003a783c25f7578
    0b000104f501000004f5010000504b01021e030a00000000000da77c5100
    0000000000000000000000060018000000000000001000ed41ba0000006f
    2f312f322f5554050003498fc25f75780b000104f501000004f501000050
    4b01021e030a00000000000da77c514b83251721000000210000000a0018
    000000000001000000a481fa0000006f2f312f322f646174655554050003
    498fc25f75780b000104f501000004f5010000504b01021e030a00000000
    0066a67c51000000000000000000000000080018000000000000001000ed
    415f0100006f2f312f322f332f5554050003108ec25f75780b000104f501
    000004f5010000504b01021e030a00000000000aa77c51ba7488890b0000
    000b0000000b0018000000000001000000a481a10100006f2f312f322f33
    2f63616c5554050003438fc25f75780b000104f501000004f5010000504b
    01021e030a0000000000d6a07c510000000000000000000000000a001800
    0000000000001000ed41f10100006f2f312f322f332f342f5554050003a4
    83c25f75780b000104f501000004f5010000504b01021e030a0000000000
    0ea77c51000000000000000000000000080018000000000000000000a481
    350200006f2f312f6e6f6e6555540500034c8fc25f75780b000104f50100
    0004f5010000504b05060000000009000900b7020000770200000000
    Output:

    3 44
  3. EJudge: BoxDrawing 'Рисуем рамочки'

    Сначала вводится строка, которая состоит из «слов», разделённых пробельными символами. В следующей строке вводится через пробел: ширина «экрана» (в знакоместах), толщина вертикальных и толщина горизонтальных линий. Толщина — это слово LIGHT или HEAVY. Требуется вывести все слова, перенося их на следующую строку и обводя рамкой. Правый край рамки должен быть выровнен по ширине экрана, лишние пробелы — добавлены к последнему слову. Слово всегда уже экрана не менее, чем на 2. Рамка набирается из UNICODE-символов блока «Box Drawing» с соответствующими именами.

    Input:

    Гнев, богиня, воспой Ахиллеса, Пелеева сына, грозный, который ахеянам тысячи бедствий соделал
    42 HEAVY LIGHT
    Output:

    ┎─────┰───────┰──────┰─────────┰─────────┒
    ┃Гнев,┃богиня,┃воспой┃Ахиллеса,┃Пелеева  ┃
    ┠─────╂───────┸┰─────┸─┰───────╂─────────┨
    ┃сына,┃грозный,┃который┃ахеянам┃тысячи   ┃
    ┠─────┸──┰─────┸───────┸───────┸─────────┨
    ┃бедствий┃соделал                        ┃
    ┖────────┸───────────────────────────────┚
    — Задача на «перевод»: какое-то описание → имя Unicode → символ
  4. — Просмотр корневого каталога в образе 1440 флоппи-диска
  5. EJudge: FragEncode 'Кодировки цитат'

    Вводится поток данных следующей структуры: в начале идёт некоторый текст в кодировке UTF-8. Затем — нулевой байт. Затем несколько фрагментов в случайной кодировке из набора CP866, CP1251, KOI8-R или ISO-8859-5, после каждого их которых снова следует нулевой байт. Для каждого фрагмента определить, является ли он (после соответствующей перекодировки) точной цитатой из текста, в этом случае вывести "Yes", идаче — "No". В примере показан шестнадцатеричный дамп, сам файл см. в приложении.

    Input:

    00000000  d0 be 20 d1 82 d0 be d0  bc 2c 20 d1 87 d1 82 d0  |.. ......, .....|
    00000010  be d0 b1 d1 8b 20 d0 b4  d1 83 d1 88 d0 b5 d0 b2  |..... ..........|
    00000020  d0 bd d0 be d0 b5 20 d0  bd d0 b0 d1 81 d1 82 d1  |...... .........|
    00000030  80 d0 be d0 b5 d0 bd d0  b8 d0 b5 20 d0 bc d0 be  |........... ....|
    00000040  d0 b3 d0 bb d0 be 20 d1  82 d0 be d1 82 d1 87 d0  |...... .........|
    00000050  b0 d1 81 20 d0 b6 d0 b5  20 d0 b8 d0 b7 d0 bc d0  |... .... .......|
    00000060  b5 d0 bd d0 b8 d1 82 d1  8c 20 d0 b5 d0 b3 d0 be  |......... ......|
    00000070  20 d0 b2 0a d1 81 d0 be  d0 bf d1 80 d0 b8 d0 ba  | ...............|
    00000080  d0 be d1 81 d0 bd d0 be  d0 b2 d0 b5 d0 bd d0 b8  |................|
    00000090  d0 b8 20 d1 81 20 d0 b4  d0 b5 d0 b9 d1 81 d1 82  |.. .. ..........|
    000000a0  d0 b2 d0 b8 d1 82 d0 b5  d0 bb d1 8c d0 bd d0 be  |................|
    000000b0  d1 81 d1 82 d1 8c d1 8e  2e 20 d0 9d d0 b5 20 d0  |......... .... .|
    000000c0  b4 d0 be d0 b5 d0 b7 d0  b6 d0 b0 d1 8f 00 de 20  |............... |
    000000d0  e2 de dc 2c 20 dd d0 e1  e2 e0 de d5 dd d8 d5 20  |..., .......... |
    000000e0  d4 e3 e8 d5 d2 dd de d5  20 e7 e2 de d1 eb 20 dc  |........ ..... .|
    000000f0  de d3 db de 00 c9 da cd  c5 ce c9 d4 d8 20 c5 c7  |............. ..|
    00000100  cf 20 d7 0a d3 cf d0 d2  c9 cb cf d3 ce cf d7 c5  |. ..............|
    00000110  ce c9 c9 20 d3 20 c4 c5  ca d3 d4 d7 c9 d4 c5 cc  |... . ..........|
    00000120  d8 ce cf d3 d4 d8 c0 2e  20 ee c5 00              |........ ...|
    Output:

    No
    Yes

LecturesCMC/PythonIntro2025/11_FilesEncodings (последним исправлял пользователь FrBrGeorge 2025-11-16 22:05:06)