Доброго времени суток, читатели, зрители моего канала programmer's notes. Не забывайте подписываться и писать свои комментарии к моим статьям и видео.
Сегодня чисто текстовый урок. Сам материал к этому располагает.
Низкоуровневая работа с файлами
Ранее мы занимались функцией open() встроенной в язык Python. Функция связывает файл файловой систем и объект, который возвращается при удачном выполнении функции. Полученный файловый объект, который также называют потоком, обладает рядом методов, которые мы уже использовали ( см. статьи ст1, ст2, ст3, ст4). Перечислю методы, не вдаваясь в их описание.
- close() — закрыть файл.
- flush() — очистить буфер чтения.
- fileno() — возвращает число - файловый дескриптор, который используется операционной системой для управления файлом.
- isatty() — возвращает True, если файл связан с текстовым терминалом.
- read() — читает весь файл или его часть.
- readline() — читает строку текстового файла.
- readlines() — читает все строки текстового файла.
- seek() — перемещает указатель в файле.
- tell() — возвращает позицию указателя в файле.
- truncate() — усекает размер файла.
- write() — пишет данные в файл.
- writelines() — пишет список строк в файл.
Объект файл может быть использован и с такой стандартной функцией как print().
Работа с файлами с помощью встроенной функции open() можно назвать высокоуровневым доступом (интерфейсом) к файлу. Язык Python предоставляет надстройку над возможностями операционной системы, определяемыми набором системных функций.
Еще один интерфейс для работы с файлами предоставляет библиотека os, в которой есть своя функция open(). Функция open() возвращает число, называемое дескриптором, которое используется для управления открытым файлом системными функциями. open() и другие функции библиотеки os для работы с открытым файлом непосредственно обращаются к системным функциям операционной системы. Такой интерфейс называют низкоуровневым.
Опишем теперь функцию open() библиотеки os.
os.open(path, flags, mode=0o777, *, dir_fd=None), где
- path — имя файла (абсолютное или относительное).
- flags — режим работы с файлом. Значения параметра определяется набором констант, объединённых битовой операцией '|'. Значения констант, которые можно использовать и в Unix-системах и в Windows:
os.O_RDONLY — открыть только для чтения;
os.O_WRONLY — открыть только для записи;
os.O_RDWR — открыть для чтения и записи;
os.O_APPEND — открыть для добавления;
os.O_CREAT — создать, если файл отсутствует;
os.O_EXCL — возвратить ошибку если файл существует. Применяется только с флагом os.O_CREAT;
os.O_TRUNC — открыть с обнулением файла. - dir_fd — дескриптор каталога, относительного которого вычисляется путь к файлу.
В библиотеке os есть методы write(d, bs) и read(d, n) для записи и чтения в файл и из фала. При этом методы работают только с байтовыми строками. Где d дескриптор файла, bs - байтовая строка, n - количество считанных байтов. При этом read() возвращает считанную байтовую строку, write() количество записанных байтов.
Ниже дан пример работы с файлом на низком уровне.
#!/usr/bin/python3
import os
ds = os.open('./tmp', os.O_WRONLY|os.O_TRUNC|os.O_CREAT, 0o666)
os.write(ds, 'привет'.encode('utf-8'))
os.close(ds)
В результате будет создан новый файл, если его не было или будет перезаписан уже существующий файл. Если файл создаётся, то права доступа определяются константой 0o666 (см. статью). При этом биты записи для других пользователей будут замаскированы umask. Чтобы справиться с этой проблемой нужно использовать метод os.chmode().
Обратимся теперь снова к встроенной функции open(). Обращаю внимание, что здесь нет возможности указать права доступа, если файл создаётся. По умолчанию даются права чтения-записи для владельца и чтения для остальных. Дело в том, что часть битов маскируется настройками umask. Обычно это 0o022. Т.е. не разрешается изменять файл посторонним пользователям.
Можно ли это как-то обойти? Можно, если открыть в начале с помощью os.open(), а потом обычным open() указав первым аргументом не путь к файлу, а дескриптор уже открытого (созданного) файла.
#!/usr/bin/python3
import os
ds = os.open('./tmp', os.O_WRONLY | os.O_CREAT, 0o777)
f1 = open(ds, 'w')
f1.write('Проверка')
f1.close()
Обратим внимание, что в данном фрагменте использование os.close(ds) не требуется. При это всё равно нам не удастся дать права записи для других пользователей. Биты записи будут замаскированы. Как уже было отмечено, чтобы преодолеть ограничение используем os.chmode().
Кроме указанных выше методов работы с открытым файлом следует отметить метод для передвижению по файлу os.lseek(d, from, to), где d - дескриптор файла, pos - количество байтов, которые следует передвинуть указатель (может быть положительным и отрицательным), how - откуда двигаем указатель: 0 - от начала, 1 - от текущей позиции, 2 - от конца файла.
Замечание.
Чтобы изменить биты umask в вашей системе в Linux есть утилита umask. Предварительно следует почитать документацию об этом инструменте. Конечно, это можно сделать и программным путём, так как библиотека os также содержит метод umask().
Хорошего программирования. Оставляйте свои комментарии, не забывайте про лайки и подписывайтесь на мой канал programmer's notes.