Исходный код dublib.Methods.Filesystem

from .Data import ToIterable

from typing import Iterable
from pathlib import Path
from os import PathLike
import tempfile
import random
import shutil
import json
import os

import orjson
import yaml

#==========================================================================================#
# >>>>> ФУНКЦИИ РАБОТЫ С ФАЙЛАМИ И ДИРЕКТОРИЯМИ <<<<< #
#==========================================================================================#

[документация] def AtomicWrite(path: PathLike, data: bytes): """ Атомарно производит запись файла в бинарном представлении, используя создание временного файла со сбросом кэша записи и операцию `os.replace()`. :param path: Путь к записываемому файлу. :type path: PathLike :param data: Набор байтов для записи. :type data: bytes """ PathObject = Path(path) TempPath = None with tempfile.NamedTemporaryFile("wb", delete = False, dir = PathObject.parent) as TempWriter: TempWriter.write(data) TempWriter.flush() os.fsync(TempWriter.fileno()) TempPath = Path(TempWriter.name) os.replace(TempPath, path)
[документация] def GetRandomFile(directory: PathLike) -> PathLike | None: """ Выбирает случайный файл из каталога. :param directory: Путь к каталогу. :type directory: PathLike :raise FileNotFoundError: Выбрасывается, если каталог не существует. :return: Путь к случайному файлу в каталоге по стандарту POSIX или `None`, если каталог пустой. :rtype: PathLike """ directory = NormalizePath(directory) Files = ListDir(directory) if not Files: return return f"{directory}/" + random.choice(Files)
[документация] def ListDir(path: PathLike | None = None) -> list[str]: """ Основана на `os.scandir()`, более быстром и подробном варианте `os.listdir()`. :param path: Путь для сканирования. Если передать `None`, будет возвращёт список элементов в текущем каталоге. :type path: PathLike | None :return: Список названий каталогов и имён файлов по указанному пути :rtype: list[str] """ return [Entry.name for Entry in os.scandir(path)]
[документация] def MakeRootDirectories(directories: Iterable[str] | str): """ Создаёт наборы каталогов в текущей корневой директории скрипта. :param directories: Последовательность названий директорий или название конкретной директории. :type directories: Iterable[str] """ directories = ToIterable(directories) for Name in directories: if not os.path.exists(Name): os.makedirs(Name)
[документация] def NormalizePath(path: PathLike, strip: bool = True) -> PathLike: """ Приводит путь к POSIX-стандарту. :param path: Обрабатываемый путь. :type path: PathLike :param strip: Указывает, следует ли удалить наклонную черту из конца пути при наличии. :type strip: bool :return: Путь в POSIX-стандарте. :rtype: PathLike """ path: str = Path(path).as_posix() if strip: path = path.rstrip("/") return path
[документация] def RemoveDirectoryContent(path: PathLike): """ Удлаляет содержимое каталога. :param path: Путь к каталогу. :type path: PathLike """ FolderContent = ListDir(path) for Item in FolderContent: ItemPath = f"{path}/{Item}" if os.path.isdir(ItemPath): shutil.rmtree(ItemPath) else: os.remove(ItemPath)
#==========================================================================================# # >>>>> ФУНКЦИИ РАБОТЫ С JSON <<<<< # #==========================================================================================#
[документация] def ReadJSON(path: PathLike) -> dict: """ Считывает файл JSON и десириализует его в словарь. :param path: Путь к файлу. :type path: PathLike :return: Словарное представление данных JSON. :rtype: dict :raises json.JSONDecodeError: Выбрасывается при невозможности десериализовать файл. :raises FileNotFoundError: Выбрасывается при отсутствии файла. """ with open(path, "rb") as FileReader: return orjson.loads(FileReader.read())
[документация] def WriteJSON(path: PathLike, data: dict, pretty: bool = True, atomic: bool = False): """ Записывает отформатированный файл JSON. :param path: Путь к файлу. :type path: PathLike :param data: Словарь для сериализации в JSON. :type data: dict :param pretty: Включает режим форматирования с использованием символов новых строк и табуляции. :type pretty: bool :param atomic: Переключает использование атомарной записи. :type atomic: bool :raise TypeError: Выбрасывается при невозможности сериализации данных в JSON. """ Content = None if pretty: Content: str = json.dumps(data, ensure_ascii = False, indent = "\t", separators = (",", ": ")).encode() else: Content: bytes = orjson.dumps(data) if atomic: AtomicWrite(path, Content) else: with open(path, "wb") as FileWriter: FileWriter.write(Content)
#==========================================================================================# # >>>>> ФУНКЦИИ РАБОТЫ С YAML <<<<< # #==========================================================================================#
[документация] def ReadYAML(path: PathLike) -> dict: """ Считывает файл YAML и десириализует его в словарь. :param path: Путь к файлу. :type path: PathLike :return: Словарное представление данных YAML. :rtype: dict :raises FileNotFoundError: Выбрасывается при отсутствии файла. """ with open(path, "r") as FileReader: return yaml.safe_load(FileReader)
[документация] def WriteYAML(path: PathLike, data: dict, atomic: bool = False): """ Записывает файл YAML. :param path: Путь к файлу. :type path: PathLike :param data: Словарь для сериализации в YAML. :type data: dict :param atomic: Переключает использование атомарной записи. :type atomic: bool """ data: str = yaml.dump(data, allow_unicode = True, sort_keys = False) if atomic: AtomicWrite(path, data.encode()) else: with open(path, "w", encoding = "utf-8") as FileWrite: FileWrite.write(data)
#==========================================================================================# # >>>>> ФУНКЦИИ РАБОТЫ С ТЕКСТОВЫМИ ФАЙЛАМИ <<<<< # #==========================================================================================#
[документация] def ReadTextFile(path: PathLike, split: bool = False, strip: bool = False) -> str | tuple[str]: """ Считывает текстовый файл. :param path: Путь к файлу. :type path: PathLike :param split: Если активировано, файл будет разбит на набор строк по символу новой строки. :type split: bool :param strip: Если активировано, к каждой возвращаемой строке будет применён метод `strip()`. :type strip: bool :return: Содержимое текстового файла в виде строки или набора строк. :rtype: str | tuple[str] :raises FileNotFoundError: Выбрасывается при отсутствии файла. """ Text = None with open(path, encoding = "utf-8") as FileReader: Text = FileReader.read() if split: Text = Text.split("\n") if strip: if type(Text) == str: Text = Text.strip() else: Text = tuple(Value.strip() for Value in Text) return Text
[документация] def WriteTextFile(path: PathLike, text: str | Iterable[str], atomic: bool = False): """ Записывает текстовый файл. :param path: Путь к файлу. :type path: PathLike :param text: Строка или последовательность строк, которые должны быть объединены через символ новой строки. :type text: str | Iterable[str] :param atomic: Переключает использование атомарной записи. :type atomic: bool """ if type(text) != str: text = "\n".join(text) if atomic: AtomicWrite(path, text.encode()) else: with open(path, "w", encoding = "utf-8") as FileWrite: FileWrite.write(text)