• Курсы Академии Кодебай, стартующие в мае - июне, от команды The Codeby

    1. Цифровая криминалистика и реагирование на инциденты
    2. ОС Linux (DFIR) Старт: 16 мая
    3. Анализ фишинговых атак Старт: 16 мая Устройства для тестирования на проникновение Старт: 16 мая

    Скидки до 10%

    Полный список ближайших курсов ...

Статья Получение размера директории с помощью Python

Эта небольшая заметка предназначена скорее для тех, кто только начинает осваивать python. Речь в ней пойдет о том, как узнать размер папки. Для тех же, кто уже давно программирует, данная информация, скорее всего, будет уже известна.

000.jpeg

Чтобы не ходить очень далеко, возьму пример из собственного опыта. Мне потребовалось узнать размер директории. Я был немного удивлен, когда узнал, что размер нельзя получить, просто запросив os.stat('путь к директории').st_size. Вернее можно, вот только возвращался стабильно одинаковый результат – 4 килобайта. Можете сами убедиться на примере. Ниже представлен небольшой скрипт, в котором, указав путь к директории (именно к директории, а не файлу), вы получите ее размер.

Python:
import os


def get_size(bts, ending='B'):
    for item in ["", "K", "M", "G", "T", "P"]:
        if bts < 1024:
            return f"{bts:.2f} {item}{ending}"
        bts /= 1024


print(get_size(os.stat(input("Введите путь к директории: ")).st_size))

Тогда я подумал, потом еще немного и попытался разобраться. Получается, что даже если вы попробуете узнать размер папки с помощью контекстного меню папки, выбрав «Свойства», результат вы получите не сразу. Пройдет некоторое время, которое будет напрямую зависеть от количества файлов, скорости жесткого диска и прочих параметров, прежде чем вы получите размер.

Подсчет размера директории в Windows

size.gif



То есть, происходит считывание размера каждого файла, находящегося во всех папках, которые есть в данном расположении. Тогда я сделал небольшой скрипт, который помог на тот момент получить размер директории. Он работает как в Windows, так и в Linux и, думаю, что для большинства задач его вполне хватит.

Здесь мы создали функцию get_size, которая будет получать размер в байтах, а возвращать уже приведенное к одному из измерений размере. Ну и функция volume, в которую передается путь к директории, с помощью функции os.walk обходятся рекурсивно все директории. Затем в каждой директории, если там есть файлы, получаем их размер и суммируем в переменной size. После чего возвращаем ее из функции.

Python:
import sys
from os import walk
from pathlib import Path


def get_size(bts, ending='B'):
    for item in ["", "K", "M", "G", "T", "P"]:
        if bts < 1024:
            return f"{bts:.2f} {item}{ending}"
        bts /= 1024


def volume(path_dir):
    size = 0
    for path, dirs, files in walk(path_dir):
        for file in files:
            size += (Path(path) / file).stat().st_size
    return size


def main():
    path = input("Введите путь к директории: ")
    if not Path(path).exists() or not Path(path).is_dir() or not path:
        print("Указанного пути не существует или введенный путь не является директорией.")
        sys.exit(0)
    print(get_size(volume(path)))


if __name__ == "__main__":
    main()

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


Импорт библиотек

Для начала импортируем нужные для работы скрипта библиотеки. Сторонних библиотек устанавливать не требуется, поэтому пишем:

Python:
import os
import sys
from pathlib import Path


Создание и инициализация класса

Создадим класс Size. При инициализации класса объявим три переменных. В переменной self.volume будет храниться общий объем указанной директории. В переменной self.count_files – будем хранить количество файлов в директории, а в переменной self.count_dirs – количество папок.

Python:
class Size:
    def __init__(self):
        self.volume = 0
        self.count_files = 0
        self.count_dirs = 0

Создадим функцию класса get_size(bts, ending='B'), которая будет являться больше вспомогательной, поэтому, сделаем ее статической. С ней, если вы смотрели предыдущий код, вы уже должны быть знакомы. Она занимается тем, что переводит байты в большие размеры.

Python:
    @staticmethod
    def get_size(bts, ending='B'):
        for item in ["", "K", "M", "G", "T", "P"]:
            if bts < 1024:
                return f"{bts:.2f} {item}{ending}"
            bts /= 1024

Создадим функцию def counting(self, size). На входе она принимает размер файла и добавляет его к общему размеру self.volume. Также, здесь выводиться в терминал информация о процессе сканирования. Поэтому, если вывод данной информации не требуется, эту строку можно просто закомментировать.

Python:
    def counting(self, size):
        self.volume += size
        print(f'\r{self.get_size(self.volume)} total, {self.count_dirs} directories and {self.count_files} '
              f'files...', end='')

Теперь создадим функцию def size_recurse(self, path), в которую будет передаваться путь к сканируемой директории. С помощью функции os.scandir получаем информацию о файлах и папках, которые находятся в целевой директории. Данная функция используется потому, что она возвращает итератор entry_it объектов os.DirEntry. В данном случае мы немного повышаем производительность нашего скрипта, так как объекты os.DirEntry предоставляют информацию о типе или атрибуте файла, если эту информацию предоставляет операционная система, а значит, нам не нужно делать дополнительный запрос, который эту информацию бы получал. В цикле итерируемся по полученным объектам, проверяем, не является ли объект директорией. Если нет, увеличиваем счетчик файлов. Считываем размер файла и передаем в функцию counting для добавления в общий размер и вывода информации в терминал. Если же получить размер файла не удается, а такое вполне может произойти, просто продолжаем итерацию.

Если же объект является директорией, увеличиваем счетчик директорий, передаем размер объекта в функцию counting для добавления. Как вы помните, размер директории в чистом виде равен 4 килобайтам. И рекурсивно запускаем функцию size_recurse, в которую передаем директорию для сканирования. После завершения всех итераций возвращаем из класса общий объем директории в байтах. Так сделано для того, чтобы можно было использовать этот объем в чистом виде.

Python:
    def size_recurse(self, path):
        try:
            for file in os.scandir(path):
                if not file.is_dir(follow_symlinks=False):
                    self.count_files += 1
                    try:
                        self.counting(file.stat().st_size)
                    except:
                        continue
                else:
                    self.count_dirs += 1
                    self.counting(file.stat(follow_symlinks=False).st_size)
                    self.size_recurse(file.path)
            return self.volume
        except OSError:
            pass

Ну и еще, сделаем наш скрипт запускаемым из командной строки. Для этого я сделал небольшой код, который получает все аргументы из командной строки. А передать в нее в качестве аргумента мы должны путь к директории, размер которой требуется узнать. Сделано это для того, чтобы, если попадется пробел в имени директории, можно было свести все аргументы вместе и передать полный путь в класс, для получения размера. Что мы и делаем. Итерируемся по всем аргументам. Я сделал их количество 100. Думаю, что вряд ли кто-то передаст в качестве параметра путь, в котором сто пробелов. И добавляем каждый найденный аргумент в список. После того, как срабатывает исключение, объединяем список, проверяем, не является ли получившийся путь пустым. Если нет, проверяем, существует ли переданный путь, является ли переданный путь директорией. И если да, передаем полученный путь в функцию класса, для получения размера. Ну, а если не выполняется какое-либо из условий, сообщаем об этом пользователю.

Python:
if __name__ == "__main__":
    path_arg = []
    try:
        for i in range(1, 101):
            if sys.argv[i]:
                path_arg.append(sys.argv[i])
    except IndexError:
        path_arg = " ".join(path_arg)
        if path_arg:
            if Path(path_arg).exists() and Path(path_arg).is_dir():
                path_vol = Size().size_recurse(path_arg)
                print(f'\n{path_vol} bytes total')
            else:
                print("Директории не существует")
        else:
            print(f"Укажите путь к директории!\nПример:\n  volume.py {Path.cwd()}\n  volume.py G:\n  volume.py /home")


Вот пример работы скрипта. Попробуем узнать объем целого диска.




Python:
import os
import sys
from pathlib import Path


class Size:
    def __init__(self):
        self.volume = 0
        self.count_files = 0
        self.count_dirs = 0

    @staticmethod
    def get_size(bts, ending='B'):
        for item in ["", "K", "M", "G", "T", "P"]:
            if bts < 1024:
                return f"{bts:.2f} {item}{ending}"
            bts /= 1024

    def counting(self, size):
        self.volume += size
        print(f'\r{self.get_size(self.volume)} total, {self.count_dirs} directories and {self.count_files} '
              f'files...', end='')

    def size_recurse(self, path):
        try:
            for file in os.scandir(path):
                if not file.is_dir(follow_symlinks=False):
                    self.count_files += 1
                    try:
                        self.counting(file.stat().st_size)
                    except:
                        continue
                else:
                    self.count_dirs += 1
                    self.counting(file.stat(follow_symlinks=False).st_size)
                    self.size_recurse(file.path)
            return self.volume
        except OSError:
            pass


if __name__ == "__main__":
    path_arg = []
    try:
        for i in range(1, 101):
            if sys.argv[i]:
                path_arg.append(sys.argv[i])
    except IndexError:
        path_arg = " ".join(path_arg)
        if path_arg:
            if Path(path_arg).exists() and Path(path_arg).is_dir():
                path_vol = Size().size_recurse(path_arg)
                print(f'\n{path_vol} bytes total')
            else:
                print("Директории не существует")
        else:
            print(f"Укажите путь к директории!\nПример:\n  volume.py {Path.cwd()}\n  volume.py G:\n  volume.py /home")

А на этом, пожалуй, все.

Спасибо за внимание. Надеюсь, данная информация будет вам полезна
 

Вложения

  • volume.zip
    889 байт · Просмотры: 108
  • Нравится
Реакции: InternetMC
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!