Прежде чем я заново изобрел этот конкретный круг, есть ли у кого-нибудь хорошая процедура для расчета размера каталога с использованием Python? Было бы очень хорошо, если бы подпрограмма хорошо форматировала размер в Мб/Гб и т.д.
Вычислить размер каталога с помощью Python?
Ответ 1
Это идет по всем подкаталогам; Суммирование размеров файла:
import os
def get_size(start_path = '.'):
total_size = 0
for dirpath, dirnames, filenames in os.walk(start_path):
for f in filenames:
fp = os.path.join(dirpath, f)
# skip if it is symbolic link
if not os.path.islink(fp):
total_size += os.path.getsize(fp)
return total_size
print(get_size(), 'bytes')
И еще один интересный способ использовать os.listdir (не включает подкаталоги):
import os
sum(os.path.getsize(f) for f in os.listdir('.') if os.path.isfile(f))
Ссылка:
- os.path.getsize - дает размер в байтах
- os.walk
- os.path.islink
Обновлено Чтобы использовать os.path.getsize, это понятнее, чем использование метода os.stat(). St_size.
Спасибо ghostdog74 за это!
os.stat - st_size Предоставляет размер в байтах. Может также использоваться для получения размера файла и другой информации, связанной с файлом.
Обновление 2018
Если вы используете Python 3.4 или более раннюю версию, вы можете рассмотреть возможность использования более эффективного метода walk
, предоставляемого сторонним пакетом scandir
. В Python 3.5 и более поздних версиях этот пакет был включен в стандартную библиотеку, и os.walk
получил соответствующее увеличение производительности.
Обновление 2019
В последнее время я использую pathlib
все больше и больше, вот решение pathlib
:
from pathlib import Path
root_directory = Path('.')
sum(f.stat().st_size for f in root_directory.glob('**/*') if f.is_file() )
Ответ 2
Некоторые из предложенных до сих пор подходов реализуют рекурсию, другие используют оболочку или не будут производить аккуратно отформатированные результаты. Когда ваш код является одноразовым для платформ Linux, вы можете получить форматирование, как обычно, рекурсию в качестве однострочного. За исключением print
в последней строке, он будет работать для текущих версий python2
и python3
:
du.py
-----
#!/usr/bin/python3
import subprocess
def du(path):
"""disk usage in human readable format (e.g. '2,1GB')"""
return subprocess.check_output(['du','-sh', path]).split()[0].decode('utf-8')
if __name__ == "__main__":
print(du('.'))
прост, эффективен и будет работать для файлов и многоуровневых каталогов:
$ chmod 750 du.py
$ ./du.py
2,9M
Немного поздно через 5 лет, но поскольку это все еще находится в хит-листах поисковых систем, это может помочь...
Ответ 3
Вот рекурсивная функция (она рекурсивно суммирует размер всех подпапок и их соответствующих файлов), которая возвращает точно такие же байты, что и при запуске "du-sb". в linux (где "." означает "текущая папка" ):
import os
def getFolderSize(folder):
total_size = os.path.getsize(folder)
for item in os.listdir(folder):
itempath = os.path.join(folder, item)
if os.path.isfile(itempath):
total_size += os.path.getsize(itempath)
elif os.path.isdir(itempath):
total_size += getFolderSize(itempath)
return total_size
print "Size: " + str(getFolderSize("."))
Ответ 4
Размер рекурсивной папки Python 3.5 с помощью os.scandir
def folder_size(path='.'):
total = 0
for entry in os.scandir(path):
if entry.is_file():
total += entry.stat().st_size
elif entry.is_dir():
total += folder_size(entry.path)
return total
Ответ 5
В принятом ответе не учитываются жесткие или непрямые ссылки и будут считать эти файлы дважды. Вы хотите отслеживать, какие индексы вы видели, и не добавлять размер для этих файлов.
import os
def get_size(start_path='.'):
total_size = 0
seen = {}
for dirpath, dirnames, filenames in os.walk(start_path):
for f in filenames:
fp = os.path.join(dirpath, f)
try:
stat = os.stat(fp)
except OSError:
continue
try:
seen[stat.st_ino]
except KeyError:
seen[stat.st_ino] = True
else:
continue
total_size += stat.st_size
return total_size
print get_size()
Ответ 6
Ответ monknut хорош, но он не работает на сломанной символической ссылке, поэтому вам также нужно проверить, действительно ли этот путь существует
if os.path.exists(fp):
total_size += os.stat(fp).st_size
Ответ 7
Ответ Криса хорош, но может быть более идиоматичным, если использовать набор для проверки каталогов, который также избегает использования исключения для потока управления:
def directory_size(path):
total_size = 0
seen = set()
for dirpath, dirnames, filenames in os.walk(path):
for f in filenames:
fp = os.path.join(dirpath, f)
try:
stat = os.stat(fp)
except OSError:
continue
if stat.st_ino in seen:
continue
seen.add(stat.st_ino)
total_size += stat.st_size
return total_size # size in bytes
Ответ 8
рекурсивный однострочный:
def getFolderSize(p):
from functools import partial
prepend = partial(os.path.join, p)
return sum([(os.path.getsize(f) if os.path.isfile(f) else getFolderSize(f)) for f in map(prepend, os.listdir(p))])
Ответ 9
Для второй части вопроса
def human(size):
B = "B"
KB = "KB"
MB = "MB"
GB = "GB"
TB = "TB"
UNITS = [B, KB, MB, GB, TB]
HUMANFMT = "%f %s"
HUMANRADIX = 1024.
for u in UNITS[:-1]:
if size < HUMANRADIX : return HUMANFMT % (size, u)
size /= HUMANRADIX
return HUMANFMT % (size, UNITS[-1])
Ответ 10
Вы можете сделать что-то вроде этого:
import commands
size = commands.getoutput('du -sh /path/').split()[0]
В этом случае я не тестировал результат перед его возвратом, если вы хотите, чтобы вы могли проверить его с помощью команд .getstatusoutput.
Ответ 11
Один слот, который вы говорите... Вот один лайнер:
sum([sum(map(lambda fname: os.path.getsize(os.path.join(directory, fname)), files)) for directory, folders, files in os.walk(path)])
Хотя я бы, вероятно, разделил его и не выполнил никаких проверок.
Чтобы преобразовать в kb см. Многоразовую библиотеку, чтобы получить удобочитаемую версию размера файла? и работать с ней в
Ответ 12
Немного поздно для вечеринки, но в одной строке при условии, что у вас glob2 и humanize. Обратите внимание, что в Python 3 по умолчанию iglob
имеет рекурсивный режим. Как изменить код для Python 3 оставлен как тривиальное упражнение для читателя.
>>> import os
>>> from humanize import naturalsize
>>> from glob2 import iglob
>>> naturalsize(sum(os.path.getsize(x) for x in iglob('/var/**'))))
'546.2 MB'
Ответ 13
Следующий script печатает размер каталога для всех подкаталогов для указанного каталога. Он также пытается извлечь выгоду (если возможно) из кеширования вызовов рекурсивных функций. Если аргумент опущен, script будет работать в текущем каталоге. Результат сортируется по размеру каталога от самых больших до самых маленьких. Поэтому вы можете адаптировать его для своих нужд.
PS Я использовал рецепт 578019 для отображения размера каталога в удобном для человека формате (http://code.activestate.com/recipes/578019/)
from __future__ import print_function
import os
import sys
import operator
def null_decorator(ob):
return ob
if sys.version_info >= (3,2,0):
import functools
my_cache_decorator = functools.lru_cache(maxsize=4096)
else:
my_cache_decorator = null_decorator
start_dir = os.path.normpath(os.path.abspath(sys.argv[1])) if len(sys.argv) > 1 else '.'
@my_cache_decorator
def get_dir_size(start_path = '.'):
total_size = 0
if 'scandir' in dir(os):
# using fast 'os.scandir' method (new in version 3.5)
for entry in os.scandir(start_path):
if entry.is_dir(follow_symlinks = False):
total_size += get_dir_size(entry.path)
elif entry.is_file(follow_symlinks = False):
total_size += entry.stat().st_size
else:
# using slow, but compatible 'os.listdir' method
for entry in os.listdir(start_path):
full_path = os.path.abspath(os.path.join(start_path, entry))
if os.path.isdir(full_path):
total_size += get_dir_size(full_path)
elif os.path.isfile(full_path):
total_size += os.path.getsize(full_path)
return total_size
def get_dir_size_walk(start_path = '.'):
total_size = 0
for dirpath, dirnames, filenames in os.walk(start_path):
for f in filenames:
fp = os.path.join(dirpath, f)
total_size += os.path.getsize(fp)
return total_size
def bytes2human(n, format='%(value).0f%(symbol)s', symbols='customary'):
"""
(c) http://code.activestate.com/recipes/578019/
Convert n bytes into a human readable string based on format.
symbols can be either "customary", "customary_ext", "iec" or "iec_ext",
see: http://goo.gl/kTQMs
>>> bytes2human(0)
'0.0 B'
>>> bytes2human(0.9)
'0.0 B'
>>> bytes2human(1)
'1.0 B'
>>> bytes2human(1.9)
'1.0 B'
>>> bytes2human(1024)
'1.0 K'
>>> bytes2human(1048576)
'1.0 M'
>>> bytes2human(1099511627776127398123789121)
'909.5 Y'
>>> bytes2human(9856, symbols="customary")
'9.6 K'
>>> bytes2human(9856, symbols="customary_ext")
'9.6 kilo'
>>> bytes2human(9856, symbols="iec")
'9.6 Ki'
>>> bytes2human(9856, symbols="iec_ext")
'9.6 kibi'
>>> bytes2human(10000, "%(value).1f %(symbol)s/sec")
'9.8 K/sec'
>>> # precision can be adjusted by playing with %f operator
>>> bytes2human(10000, format="%(value).5f %(symbol)s")
'9.76562 K'
"""
SYMBOLS = {
'customary' : ('B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'),
'customary_ext' : ('byte', 'kilo', 'mega', 'giga', 'tera', 'peta', 'exa',
'zetta', 'iotta'),
'iec' : ('Bi', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi'),
'iec_ext' : ('byte', 'kibi', 'mebi', 'gibi', 'tebi', 'pebi', 'exbi',
'zebi', 'yobi'),
}
n = int(n)
if n < 0:
raise ValueError("n < 0")
symbols = SYMBOLS[symbols]
prefix = {}
for i, s in enumerate(symbols[1:]):
prefix[s] = 1 << (i+1)*10
for symbol in reversed(symbols[1:]):
if n >= prefix[symbol]:
value = float(n) / prefix[symbol]
return format % locals()
return format % dict(symbol=symbols[0], value=n)
############################################################
###
### main ()
###
############################################################
if __name__ == '__main__':
dir_tree = {}
### version, that uses 'slow' [os.walk method]
#get_size = get_dir_size_walk
### this recursive version can benefit from caching the function calls (functools.lru_cache)
get_size = get_dir_size
for root, dirs, files in os.walk(start_dir):
for d in dirs:
dir_path = os.path.join(root, d)
if os.path.isdir(dir_path):
dir_tree[dir_path] = get_size(dir_path)
for d, size in sorted(dir_tree.items(), key=operator.itemgetter(1), reverse=True):
print('%s\t%s' %(bytes2human(size, format='%(value).2f%(symbol)s'), d))
print('-' * 80)
if sys.version_info >= (3,2,0):
print(get_dir_size.cache_info())
Пример вывода:
37.61M .\subdir_b
2.18M .\subdir_a
2.17M .\subdir_a\subdir_a_2
4.41K .\subdir_a\subdir_a_1
----------------------------------------------------------
CacheInfo(hits=2, misses=4, maxsize=4096, currsize=4)
EDIT: перемещен null_decorator выше, так как пользователь2233949 рекомендуется
Ответ 14
использовать библиотеку sh: модуль du
делает это:
pip install sh
import sh
print( sh.du("-s", ".") )
91154728 .
если вы хотите передать asterix, используйте glob
, как описано здесь.
чтобы преобразовать значения в считываемые данные человека, используйте humanize:
pip install humanize
import humanize
print( humanize.naturalsize( 91157384 ) )
91.2 MB
Ответ 15
Это удобно:
import os
import stat
size = 0
path_ = ""
def calculate(path=os.environ["SYSTEMROOT"]):
global size, path_
size = 0
path_ = path
for x, y, z in os.walk(path):
for i in z:
size += os.path.getsize(x + os.sep + i)
def cevir(x):
global path_
print(path_, x, "Byte")
print(path_, x/1024, "Kilobyte")
print(path_, x/1048576, "Megabyte")
print(path_, x/1073741824, "Gigabyte")
calculate("C:\Users\Jundullah\Desktop")
cevir(size)
Output:
C:\Users\Jundullah\Desktop 87874712211 Byte
C:\Users\Jundullah\Desktop 85815148.64355469 Kilobyte
C:\Users\Jundullah\Desktop 83803.85609722137 Megabyte
C:\Users\Jundullah\Desktop 81.83970321994275 Gigabyte
Ответ 16
Используя pathlib
я придумал этот pathlib
чтобы получить размер папки:
sum(file.stat().st_size for file in Path(folder).rglob('*'))
И вот что я придумал для красиво отформатированного вывода:
from pathlib import Path
def get_folder_size(folder):
return ByteSize(sum(file.stat().st_size for file in Path(folder).rglob('*')))
class ByteSize(int):
_kB = 1024
_suffixes = 'B', 'kB', 'MB', 'GB', 'PB'
def __new__(cls, *args, **kwargs):
return super().__new__(cls, *args, **kwargs)
def __init__(self, *args, **kwargs):
self.bytes = self.B = int(self)
self.kilobytes = self.kB = self / self._kB**1
self.megabytes = self.MB = self / self._kB**2
self.gigabytes = self.GB = self / self._kB**3
self.petabytes = self.PB = self / self._kB**4
*suffixes, last = self._suffixes
suffix = next((
suffix
for suffix in suffixes
if 1 < getattr(self, suffix) < self._kB
), last)
self.readable = suffix, getattr(self, suffix)
super().__init__()
def __str__(self):
return self.__format__('.2f')
def __repr__(self):
return '{}({})'.format(self.__class__.__name__, super().__repr__())
def __format__(self, format_spec):
suffix, val = self.readable
return '{val:{fmt}} {suf}'.format(val=val, fmt=format_spec, suf=suffix)
def __sub__(self, other):
return self.__class__(super().__sub__(other))
def __add__(self, other):
return self.__class__(super().__add__(other))
def __mul__(self, other):
return self.__class__(super().__mul__(other))
def __rsub__(self, other):
return self.__class__(super().__sub__(other))
def __radd__(self, other):
return self.__class__(super().__add__(other))
def __rmul__(self, other):
return self.__class__(super().__rmul__(other))
Использование:
>>> size = get_folder_size("c:/users/tdavis/downloads")
>>> print(size)
5.81 GB
>>> size.GB
5.810891855508089
>>> size.gigabytes
5.810891855508089
>>> size.PB
0.005674699077644618
>>> size.MB
5950.353260040283
>>> size
ByteSize(6239397620)
Я также сталкивался с этим вопросом, в котором есть несколько более компактных и, возможно, более производительных стратегий для печати размеров файлов.
Ответ 17
для получения размера одного файла, существует os.path.getsize()
>>> import os
>>> os.path.getsize("/path/file")
35L
его сообщено в байтах.
Ответ 18
Я использую python 2.7.13 с scandir, и здесь моя однострочная рекурсивная функция, чтобы получить общий размер папка:
from scandir import scandir
def getTotFldrSize(path):
return sum([s.stat(follow_symlinks=False).st_size for s in scandir(path) if s.is_file(follow_symlinks=False)]) + \
+ sum([getTotFldrSize(s.path) for s in scandir(path) if s.is_dir(follow_symlinks=False)])
>>> print getTotFldrSize('.')
1203245680
Ответ 19
Когда вычисляется размер подкаталогов, он должен обновлять размер родительской папки, и это будет продолжаться до тех пор, пока он не достигнет родительского корня.
Следующая функция вычисляет размер папки и всех ее подпапок.
import os
def folder_size(path):
parent = {} # path to parent path mapper
folder_size = {} # storing the size of directories
folder = os.path.realpath(path)
for root, _, filenames in os.walk(folder):
if root == folder:
parent[root] = -1 # the root folder will not have any parent
folder_size[root] = 0.0 # intializing the size to 0
elif root not in parent:
immediate_parent_path = os.path.dirname(root) # extract the immediate parent of the subdirectory
parent[root] = immediate_parent_path # store the parent of the subdirectory
folder_size[root] = 0.0 # initialize the size to 0
total_size = 0
for filename in filenames:
filepath = os.path.join(root, filename)
total_size += os.stat(filepath).st_size # computing the size of the files under the directory
folder_size[root] = total_size # store the updated size
temp_path = root # for subdirectories, we need to update the size of the parent till the root parent
while parent[temp_path] != -1:
folder_size[parent[temp_path]] += total_size
temp_path = parent[temp_path]
return folder_size[folder]/1000000.0
Ответ 20
Для чего это стоит... команда tree делает все это бесплатно:
tree -h --du /path/to/dir # files and dirs
tree -h -d --du /path/to/dir # dirs only
Мне нравится Python, но на сегодняшний день самым простым решением проблемы не требуется никакого нового кода.
Ответ 21
Если вы находитесь в ОС Windows, вы можете сделать:
установите модуль pywin32, запустив:
pip install pywin32
а затем кодировать следующее:
import win32com.client as com
def get_folder_size(path):
try:
fso = com.Dispatch("Scripting.FileSystemObject")
folder = fso.GetFolder(path)
size = str(round(folder.Size / 1048576))
print("Size: " + size + " MB")
except Exception as e:
print("Error --> " + str(e))
Ответ 22
Вот одна строка, которая делает это рекурсивно (рекурсивная опция доступна в Python 3.5):
import os
import glob
print(sum(os.path.getsize(f) for f in glob.glob('**', recursive=True) if os.path.isfile(f))/(1024*1024))
Ответ 23
Этот script сообщает вам, какой файл является самым большим в CWD, а также сообщает вам, в какой папке находится файл. Этот script работает для меня на win8 и python 3.3.3 shell
import os
folder=os.cwd()
number=0
string=""
for root, dirs, files in os.walk(folder):
for file in files:
pathname=os.path.join(root,file)
## print (pathname)
## print (os.path.getsize(pathname)/1024/1024)
if number < os.path.getsize(pathname):
number = os.path.getsize(pathname)
string=pathname
## print ()
print (string)
print ()
print (number)
print ("Number in bytes")
Ответ 24
По общему признанию, это своего рода хакерство и работает только в Unix/Linux.
Он соответствует du -sb .
, потому что на самом деле это оболочка Python bash, которая запускает команду du -sb .
.
import subprocess
def system_command(cmd):
""""Function executes cmd parameter as a bash command."""
p = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True)
stdout, stderr = p.communicate()
return stdout, stderr
size = int(system_command('du -sb . ')[0].split()[0])
Ответ 25
Я немного опоздал (и новичок) здесь, но я решил использовать модуль подпроцесса и командную строку 'du' с Linux, чтобы получить точное значение для размера папки в МБ. Мне пришлось использовать if и elif для корневой папки, потому что в противном случае подпроцесс вызывает ошибку из-за ненулевого возвращаемого значения.
import subprocess
import os
#
# get folder size
#
def get_size(self, path):
if os.path.exists(path) and path != '/':
cmd = str(subprocess.check_output(['sudo', 'du', '-s', path])).\
replace('b\'', '').replace('\'', '').split('\\t')[0]
return float(cmd) / 1000000
elif os.path.exists(path) and path == '/':
cmd = str(subprocess.getoutput(['sudo du -s /'])). \
replace('b\'', '').replace('\'', '').split('\n')
val = cmd[len(cmd) - 1].replace('/', '').replace(' ', '')
return float(val) / 1000000
else: raise ValueError
Ответ 26
Получить размер каталога
Свойства раствора:
- возвращает оба: видимый размер (количество байтов в файле) и фактическое дисковое пространство, используемое файлами.
- считает жестко связанные файлы только один раз
- подсчитывает символические ссылки так же, как это делает
du
- не использует рекурсию
- использует
st.st_blocks
для используемого дискового пространства, поэтому работает только в Unix-подобных системах
Код:
import os
def du(path):
if os.path.islink(path):
return (os.lstat(path).st_size, 0)
if os.path.isfile(path):
st = os.lstat(path)
return (st.st_size, st.st_blocks * 512)
apparent_total_bytes = 0
total_bytes = 0
have = []
for dirpath, dirnames, filenames in os.walk(path):
apparent_total_bytes += os.lstat(dirpath).st_size
total_bytes += os.lstat(dirpath).st_blocks * 512
for f in filenames:
fp = os.path.join(dirpath, f)
if os.path.islink(fp):
apparent_total_bytes += os.lstat(fp).st_size
continue
st = os.lstat(fp)
if st.st_ino in have:
continue # skip hardlinks which were already counted
have.append(st.st_ino)
apparent_total_bytes += st.st_size
total_bytes += st.st_blocks * 512
for d in dirnames:
dp = os.path.join(dirpath, d)
if os.path.islink(dp):
apparent_total_bytes += os.lstat(dp).st_size
return (apparent_total_bytes, total_bytes)
Пример использования:
>>> du('/lib')
(236425839, 244363264)
$ du -sb /lib
236425839 /lib
$ du -sB1 /lib
244363264 /lib
Удобочитаемый размер файла
Свойства раствора:
- Поддерживает до Yottabytes
- Поддерживает единицы СИ или Единицы МЭК
- Поддержка пользовательских суффиксов
Код:
def humanized_size(num, suffix='B', si=False):
if si:
units = ['','K','M','G','T','P','E','Z']
last_unit = 'Y'
div = 1000.0
else:
units = ['','Ki','Mi','Gi','Ti','Pi','Ei','Zi']
last_unit = 'Yi'
div = 1024.0
for unit in units:
if abs(num) < div:
return "%3.1f%s%s" % (num, unit, suffix)
num /= div
return "%.1f%s%s" % (num, last_unit, suffix)
Пример использования:
>>> humanized_size(236425839)
'225.5MiB'
>>> humanized_size(236425839, si=True)
'236.4MB'
>>> humanized_size(236425839, si=True, suffix='')
'236.4M'
Ответ 27
Решение, которое работает на Python 3.6 с использованием pathlib.
from pathlib import Path
sum([f.stat().st_size for f in Path("path").glob("**/*")])
Ответ 28
Python 3. 6+ рекурсивный размер папки/файла с использованием os.scandir
. Как мощный, как в ответ по @blakev, но короче и в ЭСПЦ стиле питона.
import os
def size(path, *, follow_symlinks=False):
try:
with os.scandir(path) as it:
return sum(size(entry, follow_symlinks=follow_symlinks) for entry in it)
except NotADirectoryError:
return os.stat(path, follow_symlinks=follow_symlinks).st_size
Ответ 29
для python3. 5+
from pathlib import Path
def get_size(path):
return sum(p.stat().st_size for p in Path(path).rglob('*'))
Ответ 30
def recursive_dir_size(path):
size = 0
for x in os.listdir(path):
if not os.path.isdir(os.path.join(path,x)):
size += os.stat(os.path.join(path,x)).st_size
else:
size += recursive_dir_size(os.path.join(path,x))
return size
Я написал эту функцию, которая дает мне точный общий размер каталога, я пробовал другие решения для циклов с os.walk, но я не знаю, почему конечный результат всегда был меньше фактического размера (в Ubuntu 18 env), Должно быть, я сделал что-то не так, но кого это волнует, написал, что этот работает отлично