Вычисление размера каталога с помощью Python?
прежде чем я заново изобрету это конкретное колесо, у кого-нибудь есть хорошая процедура для вычисления размера каталога с помощью Python? Было бы очень хорошо, если бы процедура отформатировала размер красиво в Mb/Gb и т. д.
24 ответов
это бросается в подкаталоги:
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)
total_size += os.path.getsize(fp)
return total_size
print get_size()
и oneliner для удовольствия с помощью os.listdir (не включает подкаталоги):
import os
sum(os.path.getsize(f) for f in os.listdir('.') if os.path.isfile(f))
ссылки:
os.путь.getsize не - дает размер в байтах
Обновлено Использовать os.путь.getsize не, это яснее, чем использование ОС.stat ().st_size метод.
спасибо ghostdog74 за указание на это!
os.stat - st_size дает размер в байтах. Может также использоваться для получения размера файла и другой информации, связанной с файлом.
обновить 2018
если вы используете Python 3.4 или предыдущий, вы можете использовать более эффективный walk
метод, предоставленный третьей стороной scandir
пакета. В Python 3.5 и позже этот пакет был включен в стандартную библиотеку и os.walk
получил соответствующее увеличение производительности.
некоторые из предложенных до сих пор подходов реализуют рекурсию, другие используют оболочку или не будут производить аккуратно отформатированные результаты. Когда ваш код является одноразовым для платформ 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 лет, но поскольку это все еще находится в хитлистах поисковых систем, это может помочь...
вот рекурсивная функция (она рекурсивно суммирует размер всех вложенных папок и их соответствующих файлов), которая возвращает точно такие же байты, как при запуске "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("."))
размер рекурсивной папки 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
monknut ответ хорош, но он терпит неудачу на сломанной символической ссылке, поэтому вам также нужно проверить, действительно ли этот путь существует
if os.path.exists(fp):
total_size += os.stat(fp).st_size
принятый ответ не учитывает жесткие или мягкие ссылки и будет считать эти файлы дважды. Вы хотите отслеживать, какие индексы вы видели, и не добавлять размер для этих файлов.
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()
ответ Криса хорош, но может быть сделан более идиоматичным, используя набор для проверки увиденных каталогов, что также позволяет избежать использования исключения для потока управления:
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
рекурсивный одну строчку:
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))])
для второй части вопроса
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])
вы можете сделать что-то вроде этого :
import commands
size = commands.getoutput('du -sh /path/').split()[0]
в этом случае я не тестировал результат перед его возвратом, если вы хотите, вы можете проверить его с помощью команд.getstatusoutput.
однострочный вы говорите... Вот один лайнер:
sum([sum(map(lambda fname: os.path.getsize(os.path.join(directory, fname)), files)) for directory, folders, files in os.walk(path)])
хотя я, вероятно, разделил бы его, и он не выполняет никаких проверок.
преобразовать в КБ, см. многоразовая библиотека, чтобы получить читаемую человеком версию размера файла? на
немного поздно на вечеринку, но в одной строке при условии, что у вас есть glob2 и очеловечить установлен. Обратите внимание, что в 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'
следующий скрипт печатает размер каталога всех подкаталогов для указанного каталога. Он также пытается извлечь выгоду (если это возможно) из кэширования вызовов рекурсивных функций. Если аргумент опущен, скрипт будет работать в текущем каталоге. Выходные данные сортируются по размеру каталога от самых больших до самых маленьких. Так вы можете приспособить его для ваших потребностей.
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 выше, как рекомендовал user2233949
использовать библиотеку ш модуль du
это:
pip install sh
import sh
print( sh.du("-s", ".") )
91154728 .
если вы хотите пройти asterix, используйте glob
как рассказали здесь.
чтобы преобразовать значения в человеческие считываемые, используйте очеловечить:
pip install humanize
import humanize
print( humanize.naturalsize( 91157384 ) )
91.2 MB
для получения размера одного файла существует ОС.путь.getsize не()
>>> import os
>>> os.path.getsize("/path/file")
35L
сообщается в байтах.
Если вы находитесь в ОС Windows, вы можете сделать:
установите модуль pywin32, запустив:
pip установить 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))
Это удобно:
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
этот скрипт сообщает вам, какой файл является самым большим в CWD, а также сообщает вам, в какой папке находится файл. Этот скрипт работает для меня на 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")
По общему признанию, это своего рода хакерский и работает только на Unix/Linux.
соответствует du -sb .
потому что на самом деле это оболочка Python bash, которая запускает
Я использую 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
когда размер подкаталогов вычисляется, он должен обновить размер папки своего родителя, и это будет продолжаться до тех пор, пока он не достигнет корневого родителя.
следующая функция вычисляет размер папки и всех ее вложенных папок.
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
для чего это стоит... команда tree делает все это бесплатно:
tree -h --du /path/to/dir # files and dirs
tree -h -d --du /path/to/dir # dirs only
Я люблю Python, но, безусловно, самое простое решение проблемы не требует нового кода.
Я немного опоздал (и новый) здесь, но я решил использовать модуль подпроцесса и командную строку " 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
import os
def get_size(path):
total_size = 0
for dirpath, dirnames, filenames in os.walk(path):
for f in filenames:
if os.path.exists(fp):
fp = os.path.join(dirpath, f)
total_size += os.path.getsize(fp)
return total_size # in megabytes
спасибо monkut & troex! Это работает очень хорошо!