Получить процент от байта до гб питона - PullRequest
0 голосов
/ 14 февраля 2019

Я работаю над программой, которая проверяет размер папки, а затем распечатывает процент от максимального использованного объема, который составляет 50 ГБ.Проблема, с которой я сталкиваюсь, состоит в том, что, если данные составляют только 1 МБ или небольшое число, которое не является ГБ, я не получаю точный процент.Как я могу улучшить свой код, чтобы решить эту проблему.

import math, os

def get(fold):
        total_size = 0

        for dirpath, dirnames, filenames in os.walk(fold):
            for f in filenames:
                fp = os.path.join(dirpath, f)
                size = os.path.getsize(fp)
                total_size += size

        size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
        i = int(math.floor(math.log(total_size, 1024)))
        p = math.pow(1024, i)
        s = round(total_size / p, 2)

        return "%s %s" % (s, size_name[i])

per = 100*float(get(fold))/float(5e+10)
print(per)

Ответы [ 2 ]

0 голосов
/ 14 февраля 2019

Вы немного смешиваете вещи в своем коде;например, ваша функция get() возвращает строку, но вы пытаетесь привести ее к float позже.

Я предлагаю немного ее разделить.Сначала функция для форматирования размера (я получил некоторые идеи из других вопросов stackoverflow):

SIZE_UNITS = ['', 'K', 'M', 'G', 'T']

def format_size(size_in_bytes):
    if size_in_bytes == 0:
        return '0.0 B'

    exp = math.floor(math.log(size_in_bytes, 1024))
    size = size_in_bytes / math.pow(1024, exp)
    return '{:.1f} {}B'.format(
        size,
        SIZE_UNITS[exp])

У вас есть функция для расчета размера каталога и одна для приятной печати информации:

def get_size_of_dir(dir_path):
    total_size = 0

    for dir_path, dir_list, file_list in os.walk(dir_path):
        for filename in file_list:
            f = os.path.join(dir_path, filename)
            size = os.path.getsize(f)
            total_size += size

    return total_size

def print_info(dir_path, capacity):
    total_size = get_size_of_dir(dir_path)
    percent = total_size * 100.0 / capacity

    print()
    print('Directory:     "{}"'.format(dir_path))
    print('capacity       {:>10s}'.format(format_size(capacity)))
    print('total_size     {:>10s}'.format(format_size(total_size)))
    print('percent used   {:8.1f} %'.format(percent))

Что на моей машине выглядит так:

# 1024**1 == > 1 KB
# 1024**2 == > 1 MB
# 1024**3 == > 1 GB
>>> capacity = 5 * 1024**3

>>> for folder in ('/home/ralf/Documents/', '/home/ralf/Downloads/'):
...     print_info(folder, capacity)

Directory:     "/home/ralf/Documents/"
capacity           5.0 GB
total_size       721.7 MB
percent used       14.1 %

Directory:     "/home/ralf/Downloads/"
capacity           5.0 GB
total_size         1.3 GB
percent used       25.7 %
0 голосов
/ 14 февраля 2019

Единственное место, которое вы, возможно, недооцениваете, это то, что вы добавляете размеры файлов без учета размера блока.Например, в моей системе размер блока выделения составляет 4096 байт.Так что, если я 'echo 1> test.txt', этот 1-байтовый файл занимает 4096 байт.Мы можем переработать код, чтобы попытаться учесть блоки:

import math
import os

SIZE_NAMES = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")

def get(fold):
    total_size = 0

    for dirpath, _, filenames in os.walk(fold):
        for f in filenames:
            fp = os.path.join(dirpath, f)
            stat = os.stat(fp)
            size = stat.st_blksize * math.ceil(stat.st_size / float(stat.st_blksize))
            total_size += size

    i = int(math.floor(math.log(total_size, 1024)))
    p = math.pow(1024, i)
    s = round(total_size / p, 2)

    return "%s %s" % (s, SIZE_NAMES[i])

Хотя подсчет getsize() влияет на все файлы, в процентном отношении он влияет на меньшие файлы больше.И, конечно же, узлы каталогов также занимают место.Кроме того, в этом расчете есть несколько проблем:

per = 100*float(get(fold))/float(5e+10)

Во-первых, он терпит неудачу, поскольку fold() возвращает строку, подобную '122.23 MB', которая float() не нравится.Во-вторых, в нем не учитывается единица измерения числа, которая была скорректирована в коде float(), но здесь она не скорректирована.Наконец, он не решает проблему гигабайта и гибибайта (в комментариях, если не более). Т.е. пространство уменьшается на 1024 в коде fold(), но здесь делится на 1000.Моя переделка:

number, unit = get(fold).split()  # "2.34 MB" -> ["2.34", "MB"]
number = float(number) * 1024 ** SIZE_NAMES.index(unit)  # 2.34 * 1024 ** 2
print("{0:%}".format(number / 500e9))  # percentage of 500GB
...