पायथन में फ़ाइल आकार बदलने का बेहतर तरीका


84

मैं एक पुस्तकालय का उपयोग कर रहा हूं जो एक फ़ाइल पढ़ता है और बाइट में इसका आकार देता है।

यह फ़ाइल आकार तब अंतिम उपयोगकर्ता को प्रदर्शित किया जाता है; उन्हें समझने के लिए यह आसान बनाने के लिए, मैं स्पष्ट रूप से फ़ाइल आकार को इसके MBद्वारा विभाजित करके परिवर्तित कर रहा हूं 1024.0 * 1024.0। बेशक यह काम करता है, लेकिन मैं सोच रहा हूं कि पायथन में ऐसा करने का एक बेहतर तरीका है?

बेहतर तरीके से, मेरा मतलब है कि शायद एक stdlib फ़ंक्शन जो कि मेरे इच्छित प्रकार के अनुसार आकारों में हेरफेर कर सकता है। जैसे अगर मैं निर्दिष्ट MBकरता हूं , तो यह स्वचालित रूप से इसे विभाजित करता है 1024.0 * 1024.0। इन पंक्तियों पर गौर करें।


4
तो एक लिख दो। यह भी ध्यान दें कि कई सिस्टम अब MB का उपयोग 2 ^ 20 के बजाय 10 ^ 6 का मतलब करते हैं।
टीसी

5
@AA, @tc: कृपया ध्यान रखें कि SI और IEC नॉर्म है kB (Kilo) for 1.000 Byteऔर KiB (Kibi) for 1.024 ByteEn.wikipedia.org/wiki/Kibibyte देखें ।
बॉबी

2
@ लॉबी: kB का वास्तव में मतलब है "किलोबेल", 10000 dB के बराबर। बाइट के लिए कोई एसआई यूनिट नहीं है। IIRC, IEC KiB की सिफारिश करता है लेकिन kB या KB को परिभाषित नहीं करता है।
टीसी

2
@tc। उपसर्ग किलो को SI द्वारा 1000 से परिभाषित किया जाता है। IEC परिभाषित kB, आदि 2 ^ 10 के बजाय SI उपसर्ग का उपयोग करता है।
ford

1
मेरा मतलब है कि उपसर्गों को आमतौर पर SI द्वारा परिभाषित किया जाता है, लेकिन डेटा आकार के लिए संक्षिप्ताक्षर नहीं हैं: Phys.nist.gov/cuu/Units/prefixes.html । जिन्हें IEC द्वारा परिभाषित किया गया है: Phys.nist.gov/cuu/Units/binary.html
ford

जवाबों:


100

वहाँ है। जल्दी करो कि आकार बाइट्स में ले जाएगा और एक अच्छा स्ट्रिंग बाहर अगर यह।

>>> from hurry.filesize import size
>>> size(11000)
'10K'
>>> size(198283722)
'189M'

या यदि आप 1K == 1000 चाहते हैं (जो कि अधिकांश उपयोगकर्ता मानते हैं):

>>> from hurry.filesize import size, si
>>> size(11000, system=si)
'11K'
>>> size(198283722, system=si)
'198M'

इसका आईईसी समर्थन भी है (लेकिन यह दस्तावेज नहीं था):

>>> from hurry.filesize import size, iec
>>> size(11000, system=iec)
'10Ki'
>>> size(198283722, system=iec)
'189Mi'

क्योंकि यह बहुत बढ़िया मार्टिज़न फासेन द्वारा लिखा गया है, कोड छोटा, स्पष्ट और एक्स्टेंसिबल है। अपने सिस्टम को लिखना आसान है।

यहाँ एक है:

mysystem = [
    (1024 ** 5, ' Megamanys'),
    (1024 ** 4, ' Lotses'),
    (1024 ** 3, ' Tons'), 
    (1024 ** 2, ' Heaps'), 
    (1024 ** 1, ' Bunches'),
    (1024 ** 0, ' Thingies'),
    ]

ऐसे इस्तेमाल किया:

>>> from hurry.filesize import size
>>> size(11000, system=mysystem)
'10 Bunches'
>>> size(198283722, system=mysystem)
'189 Heaps'

1
हम्म, अब मुझे दूसरे रास्ते पर जाने के लिए एक की जरूरत है। "1 केबी" से 1024(एक इंट)।
mlissner

2
केवल अजगर 2 में काम करता है
ई-जानकारी128

2
यह पैकेज शांत हो सकता है, लेकिन विषम लाइसेंस और यह तथ्य कि कोई ऑनलाइन उपलब्ध स्रोत कोड नहीं है, यह ऐसा कुछ है जिससे मैं बचने में बहुत खुश हूं। और यह भी केवल python2 का समर्थन करने लगता है।
अल्मोग कोहेन

1
@AlmogCohen स्रोत ऑनलाइन है, सीधे PyPI से उपलब्ध है (कुछ पैकेजों में Github रिपॉजिटरी नहीं है, बस PyPI पेज है) और लाइसेंस यह अस्पष्ट नहीं है, ZPL Zope Z का लाइसेंस है, जो मेरे ज्ञान के सर्वश्रेष्ठ के लिए है , BSD जैसी मैं मानता हूँ कि लाइसेंसिंग विषम है: कोई मानक 'LICENSE.txt' फ़ाइल नहीं है, और न ही प्रत्येक स्रोत फ़ाइल के शीर्ष पर कोई प्रस्तावना है।
स्लीवलैक

1
मेगाबाइट प्राप्त करने के लिए मैंने MBFACTOR = float(1 << 20); mb= int(size_in_bytes) / MBFACTOR बिटवाइज शिफ्टिंग ऑपरेटर का उपयोग करते हुए समीकरण का पालन किया: @LennartRegebro
alper

147

यहाँ मेरा उपयोग है:

import math

def convert_size(size_bytes):
   if size_bytes == 0:
       return "0B"
   size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
   i = int(math.floor(math.log(size_bytes, 1024)))
   p = math.pow(1024, i)
   s = round(size_bytes / p, 2)
   return "%s %s" % (s, size_name[i])

NB: आकार बाइट्स में भेजा जाना चाहिए।


11
यदि आप बाइट में आकार भेज रहे हैं, तो बस size_name के पहले तत्व के रूप में "B" जोड़ें।
tuxGurl

जब आपके पास फ़ाइल का 0 आकार बाइट होता है, तो यह विफल हो जाता है। लॉग (0, 1024) परिभाषित नहीं है! आपको इस कथन से पहले 0 बाइट मामले की जाँच करनी चाहिए i = int (math.floor (math.log (size, 1024)))।
genclik27

genclik - आप सही कह रहे हैं। मैंने अभी एक मामूली संपादन प्रस्तुत किया है जो इसे ठीक करेगा, और बाइट्स से रूपांतरण को सक्षम करेगा। धन्यवाद,
सपम

HI @HK के रूप में tuxGurl ने इसके आसान समाधान का उल्लेख किया।
जेम्स

3
वास्तव में आकार के नाम ("B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB") की आवश्यकता होगी। अधिक जानकारी के लिए en.wikipedia.org/wiki/Mebibyte देखें ।
एलेक्स

36

आकार के बजाए आप के एक बिटवाइजर शिफ्टिंग ऑपरेटर का1024 * 1024 उपयोग कर सकते हैं , अर्थात मेगाबाइट पाने के लिए, गीगाबाइट पाने के लिए, आदि।<< 1<<201<<30

सबसे सरल परिदृश्य में आप उदाहरण के लिए एक स्थिरांक है MBFACTOR = float(1<<20)जो तब बाइट्स के साथ इस्तेमाल किया जा सकता है, अर्थात् megas = size_in_bytes/MBFACTOR:।

मेगाबाइट आमतौर पर वे सभी होते हैं जिनकी आपको आवश्यकता होती है, या अन्यथा ऐसा कुछ उपयोग किया जा सकता है:

# bytes pretty-printing
UNITS_MAPPING = [
    (1<<50, ' PB'),
    (1<<40, ' TB'),
    (1<<30, ' GB'),
    (1<<20, ' MB'),
    (1<<10, ' KB'),
    (1, (' byte', ' bytes')),
]


def pretty_size(bytes, units=UNITS_MAPPING):
    """Get human-readable file sizes.
    simplified version of https://pypi.python.org/pypi/hurry.filesize/
    """
    for factor, suffix in units:
        if bytes >= factor:
            break
    amount = int(bytes / factor)

    if isinstance(suffix, tuple):
        singular, multiple = suffix
        if amount == 1:
            suffix = singular
        else:
            suffix = multiple
    return str(amount) + suffix

print(pretty_size(1))
print(pretty_size(42))
print(pretty_size(4096))
print(pretty_size(238048577))
print(pretty_size(334073741824))
print(pretty_size(96995116277763))
print(pretty_size(3125899904842624))

## [Out] ###########################
1 byte
42 bytes
4 KB
227 MB
311 GB
88 TB
2 PB


2
@Tjorriemorrie: यह एक लेफ्ट शिफ्ट होना चाहिए, राइट शिफ्टिंग से केवल थोड़ी सी गिरावट आएगी और इसके परिणामस्वरूप होगा 0
ccpindra

शानदार जवाब। धन्यवाद।
बोरिस्लाव आइमलाइव

मुझे पता है कि यह पुराना है, लेकिन क्या यह सही उपयोग होगा? def Convert_to_mb (data_b): प्रिंट (data_b / (1 << 20))
roastbeeef

22

यहां आकार की गणना करने के लिए कॉम्पैक्ट फ़ंक्शन है

def GetHumanReadable(size,precision=2):
    suffixes=['B','KB','MB','GB','TB']
    suffixIndex = 0
    while size > 1024 and suffixIndex < 4:
        suffixIndex += 1 #increment the index of the suffix
        size = size/1024.0 #apply the division
    return "%.*f%s"%(precision,size,suffixes[suffixIndex])

अधिक विस्तृत आउटपुट और इसके विपरीत ऑपरेशन के लिए कृपया देखें: http://code.activestate.com/recipes/578019-bytes-to-human-human-to-bytes-converter/


12

यदि आप पहले से ही चाहते हैं कि कोड की एक पंक्ति में फ़ाइल आकार मुद्रित करने के लिए एक त्वरित और अपेक्षाकृत आसान तरीका पढ़ने के लिए नीचे देखें। ये वन-लाइनर्स ऊपर दिए गए शानदार उत्तर को @ccpizza द्वारा संयोजित करते हैं, कुछ आसान फ़ॉर्मेटिंग ट्रिक्स के साथ मैंने यहाँ पढ़ा कि हजारों विभाजकों के रूप में अल्पविराम के साथ संख्या कैसे प्रिंट करें?

बाइट्स

print ('{:,.0f}'.format(os.path.getsize(filepath))+" B")

किलोबिट्स

print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<7))+" kb")

किलोबाइट

print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<10))+" KB")

मेगाबिट्स

print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<17))+" mb")

मेगाबाइट

print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<20))+" MB")

gigabits

print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<27))+" gb")

गीगाबाइट

print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<30))+" GB")

टेराबाइट

print ('{:,.0f}'.format(os.path.getsize(filepath)/float(1<<40))+" TB")

स्पष्ट रूप से वे मानते हैं कि आप मोटे तौर पर जानते हैं कि आप किस आकार की शुरुआत से निपटने जा रहे हैं, जो मेरे मामले में (दक्षिण पश्चिम लंदन टीवी पर वीडियो संपादक) एमबी और कभी-कभी वीडियो क्लिप के लिए जीबी है।


अद्यतन करने का तरीका Hildy की टिप्पणी के जवाब में, यहाँ केवल पायथन मानक पुस्तकालय का उपयोग करके कार्यों की एक कॉम्पैक्ट जोड़ी (चीजों को विलय करने के बजाय 'परमाणु रखते हुए) के लिए मेरा सुझाव है:

from pathlib import Path    

def get_size(path = Path('.')):
    """ Gets file size, or total directory size """
    if path.is_file():
        size = path.stat().st_size
    elif path.is_dir():
        size = sum(file.stat().st_size for file in path.glob('*.*'))
    return size

def format_size(path, unit="MB"):
    """ Converts integers to common size units used in computing """
    bit_shift = {"B": 0,
            "kb": 7,
            "KB": 10,
            "mb": 17,
            "MB": 20,
            "gb": 27,
            "GB": 30,
            "TB": 40,}
    return "{:,.0f}".format(get_size(path) / float(1 << bit_shift[unit])) + " " + unit

# Tests and test results
>>> format_size("d:\\media\\bags of fun.avi")
'38 MB'
>>> format_size("d:\\media\\bags of fun.avi","KB")
'38,763 KB'
>>> format_size("d:\\media\\bags of fun.avi","kb")
'310,104 kb'

1
यह एक बहुत चालाक तरीका है। मुझे आश्चर्य है कि अगर आप इन्हें एक फंक्शन में डाल सकते हैं, जिसमें आप पास चाहते हैं कि क्या आप केबी चाहते हैं। एमबी और इतने पर। आपके पास एक इनपुट कमांड भी हो सकता है जो पूछता है कि आप कौन सा चाहते हैं, जो कि अगर आप ऐसा करते हैं तो यह बहुत सुविधाजनक होगा।
हिल्डी

ऊपर देखें, Hildy ... आप ऊपर दिए गए @ lennart-regebro जैसी डिक्शनरी लाइन को भी कस्टमाइज़ कर सकते हैं ... जो स्टोरेज मैनेजमेंट के लिए उपयोगी हो सकती है, जैसे "विभाजन", "क्लस्टर", "4TB डिस्क", "DVD_RW," ब्लू-रे डिस्क "," 1 जीबी मेमोरी स्टिक "या जो भी हो।
पीटर एफ

मैंने अभी भी Kb (Kilobit), Mb (Megabit), और Gb (Gigabit) को जोड़ा है - उपयोगकर्ता अक्सर नेटवर्क या फ़ाइल-स्थानांतरण गति के मामले में भ्रमित होते हैं, इसलिए सोचा कि यह आसान हो सकता है।
पीटर एफ

9

बस अगर किसी को इस समस्या का उल्टा पता चलता है (जैसा कि मुझे यकीन है) यहाँ मेरे लिए क्या काम करता है:

def get_bytes(size, suffix):
    size = int(float(size))
    suffix = suffix.lower()

    if suffix == 'kb' or suffix == 'kib':
        return size << 10
    elif suffix == 'mb' or suffix == 'mib':
        return size << 20
    elif suffix == 'gb' or suffix == 'gib':
        return size << 30

    return False

आप 1.5GB जैसे दशमलव संख्या के मामले को नहीं संभाल रहे हैं। यह सिर्फ बदलने को ठीक करने के << 10लिए * 1024, << 20करने के लिए * 1024**2और << 30करने के लिए * 1024**3
E235

3

यह रहा:

def convert_bytes(size):
   for x in ['bytes', 'KB', 'MB', 'GB', 'TB']:
       if size < 1024.0:
           return "%3.1f %s" % (size, x)
       size /= 1024.0

   return size

2

यहाँ मेरे दो सेंट हैं, जो ऊपर और नीचे कास्टिंग की अनुमति देता है, और अनुकूलन योग्य सटीकता जोड़ता है:

def convertFloatToDecimal(f=0.0, precision=2):
    '''
    Convert a float to string of decimal.
    precision: by default 2.
    If no arg provided, return "0.00".
    '''
    return ("%." + str(precision) + "f") % f

def formatFileSize(size, sizeIn, sizeOut, precision=0):
    '''
    Convert file size to a string representing its value in B, KB, MB and GB.
    The convention is based on sizeIn as original unit and sizeOut
    as final unit. 
    '''
    assert sizeIn.upper() in {"B", "KB", "MB", "GB"}, "sizeIn type error"
    assert sizeOut.upper() in {"B", "KB", "MB", "GB"}, "sizeOut type error"
    if sizeIn == "B":
        if sizeOut == "KB":
            return convertFloatToDecimal((size/1024.0), precision)
        elif sizeOut == "MB":
            return convertFloatToDecimal((size/1024.0**2), precision)
        elif sizeOut == "GB":
            return convertFloatToDecimal((size/1024.0**3), precision)
    elif sizeIn == "KB":
        if sizeOut == "B":
            return convertFloatToDecimal((size*1024.0), precision)
        elif sizeOut == "MB":
            return convertFloatToDecimal((size/1024.0), precision)
        elif sizeOut == "GB":
            return convertFloatToDecimal((size/1024.0**2), precision)
    elif sizeIn == "MB":
        if sizeOut == "B":
            return convertFloatToDecimal((size*1024.0**2), precision)
        elif sizeOut == "KB":
            return convertFloatToDecimal((size*1024.0), precision)
        elif sizeOut == "GB":
            return convertFloatToDecimal((size/1024.0), precision)
    elif sizeIn == "GB":
        if sizeOut == "B":
            return convertFloatToDecimal((size*1024.0**3), precision)
        elif sizeOut == "KB":
            return convertFloatToDecimal((size*1024.0**2), precision)
        elif sizeOut == "MB":
            return convertFloatToDecimal((size*1024.0), precision)

TBअपनी इच्छानुसार जोड़ें , आदि।


मैं इसे वोट करूंगा क्योंकि यह सिर्फ पायथन मानक पुस्तकालय के साथ काम किया जा सकता है
Ciasto piekarz

1

यहाँ एक संस्करण है जो ls -lh के आउटपुट से मेल खाता है ।

def human_size(num: int) -> str:
    base = 1
    for unit in ['B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']:
        n = num / base
        if n < 9.95 and unit != 'B':
            # Less than 10 then keep 1 decimal place
            value = "{:.1f}{}".format(n, unit)
            return value
        if round(n) < 1000:
            # Less than 4 digits so use this
            value = "{}{}".format(round(n), unit)
            return value
        base *= 1024
    value = "{}{}".format(round(n), unit)
    return value

1
UNITS = {1000: ['KB', 'MB', 'GB'],
            1024: ['KiB', 'MiB', 'GiB']}

def approximate_size(size, flag_1024_or_1000=True):
    mult = 1024 if flag_1024_or_1000 else 1000
    for unit in UNITS[mult]:
        size = size / mult
        if size < mult:
            return '{0:.3f} {1}'.format(size, unit)

approximate_size(2123, False)

यह कई सेटिंग्स में प्रयोग करने योग्य है। मुझे इस टिप्पणी पर खुशी हुई। बहुत बहुत धन्यवाद।
सौरभ जैन

0

यहाँ मेरा कार्यान्वयन है:

from bisect import bisect

def to_filesize(bytes_num, si=True):
    decade = 1000 if si else 1024
    partitions = tuple(decade ** n for n in range(1, 6))
    suffixes = tuple('BKMGTP')

    i = bisect(partitions, bytes_num)
    s = suffixes[i]

    for n in range(i):
        bytes_num /= decade

    f = '{:.3f}'.format(bytes_num)

    return '{}{}'.format(f.rstrip('0').rstrip('.'), s)

यह तीन दशमलव तक प्रिंट करेगा और यह शून्य और अवधियों को पीछे छोड़ता है। बूलियन पैरामीटर si10-आधारित बनाम 2-आधारित आकार परिमाण के उपयोग को चालू करेगा।

यह इसका प्रतिपक्ष है। यह जैसे साफ विन्यास फाइल लिखने की अनुमति देता है {'maximum_filesize': from_filesize('10M')। यह एक पूर्णांक देता है जो इच्छित फ़ाइलों का अनुमान लगाता है। मैं बिट शिफ्टिंग का उपयोग नहीं कर रहा हूं क्योंकि स्रोत मूल्य एक फ्लोटिंग पॉइंट नंबर है (यह from_filesize('2.15M')ठीक स्वीकार करेगा )। इसे एक पूर्णांक / दशमलव में बदलना काम करेगा लेकिन कोड को और अधिक जटिल बनाता है और यह पहले से ही जैसा है वैसा ही काम करता है।

def from_filesize(spec, si=True):
    decade = 1000 if si else 1024
    suffixes = tuple('BKMGTP')

    num = float(spec[:-1])
    s = spec[-1]
    i = suffixes.index(s)

    for n in range(i):
        num *= decade

    return int(num)

-1

यहाँ @ रोमियो के रिवर्स कार्यान्वयन का एक और संस्करण है जो एकल इनपुट स्ट्रिंग को संभालता है।

import re

def get_bytes(size_string):
    try:
        size_string = size_string.lower().replace(',', '')
        size = re.search('^(\d+)[a-z]i?b$', size_string).groups()[0]
        suffix = re.search('^\d+([kmgtp])i?b$', size_string).groups()[0]
    except AttributeError:
        raise ValueError("Invalid Input")
    shft = suffix.translate(str.maketrans('kmgtp', '12345')) + '0'
    return int(size) << int(shft)

-1

हारून ड्यूक के जवाब के समान लेकिन अधिक "पायथोनिक";)

import re


RE_SIZE = re.compile(r'^(\d+)([a-z])i?b?$')

def to_bytes(s):
    parts = RE_SIZE.search(s.lower().replace(',', ''))
    if not parts:
        raise ValueError("Invalid Input")
    size = parts.group(1)
    suffix = parts.group(2)
    shift = suffix.translate(str.maketrans('kmgtp', '12345')) + '0'
    return int(size) << int(shift)

-1

मैं प्रोग्रामिंग में नया हूँ। मैं इस निम्नलिखित फ़ंक्शन के साथ आया था जो किसी दिए गए फ़ाइल आकार को पठनीय प्रारूप में परिवर्तित करता है।

def file_size_converter(size):
    magic = lambda x: str(round(size/round(x/1024), 2))
    size_in_int = [int(1 << 10), int(1 << 20), int(1 << 30), int(1 << 40), int(1 << 50)]
    size_in_text = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
    for i in size_in_int:
        if size < i:
            g = size_in_int.index(i)
            position = int((1024 % i) / 1024 * g)
            ss = magic(i)
            return ss + ' ' + size_in_text[position]

-2

सभी फ़ाइल आकारों के लिए यह सही ढंग से काम करता है:

import math
from os.path import getsize

def convert_size(size):
   if (size == 0):
       return '0B'
   size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
   i = int(math.floor(math.log(size,1024)))
   p = math.pow(1024,i)
   s = round(size/p,2)
   return '%s %s' % (s,size_name[i])

print(convert_size(getsize('file_name.zip')))

3
क्या यह वास्तव में "सपम" से उत्तर को कॉपी करने लायक था .... नहीं .... बस अगली बार टिप्पणी करें।
गुस्सा 84

एक अन्य उत्तर को कहीं और कॉपी किया जाना चाहिए और फिर यहां कॉपी किया जाना चाहिए ... हम मूल लोगों को प्रोत्साहित करते हैं, वास्तव में।
WesternGun
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.