11.26 Работа с файлами
TODO Too long, make examples cumulative
Просто файлы
- текстовые и бинарные файлы (остальное вроде бы очевидно)
Открытие двоичного файла с русским текстом, чтение по байту оттуда
поменять местами половины бинарного файла
Вывести первую треть текстового файла, довыведя последнюю строку целиком (до "\n")
треть отсчитывается от числа символов (не байтов) в файле, "\n" тоже считается символом
Кодировки
- Кодировки — в файлах или I/O, а некий вариант unicode (UCS16) — внутри Python
locale.getdefaultlocale()
encdode() и .decode()
преобразовать слово "вопрос" в "БНОПНЯ" с помощью encdode() и decode(); найти слова, из которых можно получить тем же способом "бМХЛЮМХЕ" и "ОХРЮМХЕ" (используются кодировки cp1251 и koi8-r)
Сериализация
Pickle
простые примеры dump()/load()
поглядеть глазками protocol=0
класс с сериализацией
реализуйте класс SerCls с полями lst (список), dct (словарь), num (число), st (строка)
cоздайте экземпляр ser этого класса с непустым наполнением всех полей
сериализуйте ser в строку, удалите ser
десериализуйте строку в новый экземпляр ser1 класса SerCls
Типизированные бинарные файлы
Применение, язык описания структур
проблемы: порядок байтов и выравнивание
Заполнить двоичный файл 10-ю случайными тройками float, bytes[3], int
- TODO: чтобы не тянуть в упражненьку random(), придумать более простую генерацию троек для файла. Например: (0.1, [1,2,3], 11); (0.2, [2,3,4], 12); (0.3, [3,4,5], 13)
Прочитать тройки float, bytes[3], int из файла, записать их в файл с сетевым порядком байтов
Сравним эти файлы (например, в linux с помощью hexdump -C или в python — binascii.hexlify(Bytes, ' '))
Ближе к практике
FIXME: это уже не успели, оставить одно из <БкП, IO>; при этом IO зависит от БкП!
Командная строка и sys.argv
Использование pathlib
Использование binascii.html (в частности hexlify)
Написать программу, которая получает один параметр в командной строке — имя файла — и выводит его шестнадцатеричный дамп (например, по 16 байтов в строке).
Оформить функцию dump(file), которой передаётся открытый файл, а она выводит дамп
IO
Модуль io, в частности StringIO
Написать программу, которая может получать один параметр в командной строке
- Если в параметре указано имя существующего файла, выводится его дамп
Если в параметре указано имя несуществующего файла, выводится дамп самого этого имени (с использованием BytesIO)
Если параметра нет, выводится дамп sys.stdin.buffer
Д/З
Задача_1:
Ввести со стандартного ввода и вывести на стандартный вывод бинарные данные, первый байт которых — это количество N равных (с точностью до ±1 байта) частей, на которые нужно разделить остальной ввод (далее - "хвост"), отсортировать эти части между собой по возрастанию, и вывести на стандартный вывод (вместе со стартовым байтом вначале).
Бинарное чтение / запись — из потока sys.stdin.buffer и в sys.stdout.buffer
- Границы частей вычисляются (если они не целые, пускай Питон сам округляет) по формуле i*L/N …(i+1)*L/N, где i — номер части (от 0 до N-1), L — размер хвоста ввода, а N — количество частей
Минимум по одному тесту на три случая: размер хвоста кратен N, не кратен N, меньше N (тогда некоторые части просто пустые)
Input: (без перевода строки в конце; первое ! — это число 33)
!qqwweerrttyyuuiiooppaassddffgghhjjkkllzzxxccvvbbnnmm66554433221100
Output:
!00112233445566aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz
Input: (без перевода строки в конце; первое $ — это число 36)
$cCbBaA
Output:
$ABCabc
Задача_2:
Написать перекодировщик в UTF8 для следующей ситуации:
был текст на русском в кодировке CP1251
этот текст был перекодирован в UTF8 как если бы он был в кодировке latin1 (типичная ситуация с mp3 тегами ID3v1)
На входе — что-то типа áûë òåêñò íà ðóññêîì â êîäèðîâêå (ввод заканчивается концом файла ☺)
- На выходе — русский текст
- Несоответствующие кодировке символы заменять на «"?"» (что .decode/encode умеет сам)
- Минимум по одному тесту на два случая: есть или нет несоответствующих символов
Input:
ûë òåêñò íà ðóññêîì â êîäèðîâêå â êîâèä
Output:
ыл текст на русском в кодировке в ковид
Задача_3:
Вывести заголовок wav-файла (не весь, нужные поля отмечены )
Size=…, Type=…, Channels=…, Rate=…, Bits=…, Data size=…
- если это не WAV (проверить строковые маркеры), вывести "NO"
Сделать минимум три теста:
- Успешный (настоящий wav)
Неуспешный (заголовок не распознаётся, например, потому что сам файл короче заголовка)
- Неуспешный (заголовок прочтён, но строковые маркеры не совпадают)
- Структура wav-файла:
Positions off-by-1
Sample Value
Description
1 - 4
"RIFF"
Marks the file as a riff file. Characters are each 1 byte long.
5 - 8
File size (integer)
Size of the overall file in bytes - 4 bytes (32-bit integer). Typically, you'd fill this in after creation.
9 -12
"WAVE"
File Type Header. For our purposes, it always equals "WAVE".
13-16
"fmt "
Format chunk marker. Includes trailing null
17-20
16
Length of format data as listed above
21-22
1
Type of format (1 is PCM) - 2 byte integer
23-24
2
Number of Channels - 2 byte integer
25-28
44100
Sample Rate - 32 byte integer. Common values are 44100 (CD), 48000 (DAT). Sample Rate = Number of Samples per second, or Hertz.
29-32
176400
(Sample Rate * BitsPerSample * Channels) / 8.
33-34
4
(BitsPerSample * Channels) / 8.1 - 8 bit mono2 - 8 bit stereo/16 bit mono4 - 16 bit stereo
35-36
16
Bits per sample
37-40
"data"
"data" chunk header. Marks the beginning of the data section.
41-44
File size (data)
Size of the data section.
Input (1):
LecturesCMC/PythonIntro2021/Prac/10_Files/phone.wav
Output (1):
Size=108208, Type=1, Channels=2, Rate=44100, Bits=16, Data size=108172
Input (2):
Output (2):
NO