github.com/kubesphere/s2irun@v3.2.1+incompatible/pkg/utils/bytefmt/bytes.go (about)

     1  // Package bytefmt contains helper methods and constants for converting to and from a human-readable byte format.
     2  //
     3  //	bytefmt.ByteSize(100.5*bytefmt.MEGABYTE) // "100.5M"
     4  //	bytefmt.ByteSize(uint64(1024)) // "1K"
     5  //
     6  package bytefmt
     7  
     8  import (
     9  	"errors"
    10  	"strconv"
    11  	"strings"
    12  	"unicode"
    13  )
    14  
    15  const (
    16  	BYTE = 1 << (10 * iota)
    17  	KILOBYTE
    18  	MEGABYTE
    19  	GIGABYTE
    20  	TERABYTE
    21  	PETABYTE
    22  	EXABYTE
    23  )
    24  
    25  var invalidByteQuantityError = errors.New("byte quantity must be a positive integer with a unit of measurement like M, MB, MiB, G, GiB, or GB")
    26  
    27  // ByteSize returns a human-readable byte string of the form 10M, 12.5K, and so forth.  The following units are available:
    28  //	E: Exabyte
    29  //	P: Petabyte
    30  //	T: Terabyte
    31  //	G: Gigabyte
    32  //	M: Megabyte
    33  //	K: Kilobyte
    34  //	B: Byte
    35  // The unit that results in the smallest number greater than or equal to 1 is always chosen.
    36  func ByteSize(bytes uint64) string {
    37  	unit := ""
    38  	value := float64(bytes)
    39  
    40  	switch {
    41  	case bytes >= EXABYTE:
    42  		unit = "E"
    43  		value = value / EXABYTE
    44  	case bytes >= PETABYTE:
    45  		unit = "P"
    46  		value = value / PETABYTE
    47  	case bytes >= TERABYTE:
    48  		unit = "T"
    49  		value = value / TERABYTE
    50  	case bytes >= GIGABYTE:
    51  		unit = "G"
    52  		value = value / GIGABYTE
    53  	case bytes >= MEGABYTE:
    54  		unit = "M"
    55  		value = value / MEGABYTE
    56  	case bytes >= KILOBYTE:
    57  		unit = "K"
    58  		value = value / KILOBYTE
    59  	case bytes >= BYTE:
    60  		unit = "B"
    61  	case bytes == 0:
    62  		return "0"
    63  	}
    64  
    65  	result := strconv.FormatFloat(value, 'f', 1, 64)
    66  	result = strings.TrimSuffix(result, ".0")
    67  	return result + unit
    68  }
    69  
    70  // ToMegabytes parses a string formatted by ByteSize as megabytes.
    71  func ToMegabytes(s string) (uint64, error) {
    72  	bytes, err := ToBytes(s)
    73  	if err != nil {
    74  		return 0, err
    75  	}
    76  
    77  	return bytes / MEGABYTE, nil
    78  }
    79  
    80  // ToBytes parses a string formatted by ByteSize as bytes. Note binary-prefixed and SI prefixed units both mean a base-2 units
    81  // KB = K = KiB	= 1024
    82  // MB = M = MiB = 1024 * K
    83  // GB = G = GiB = 1024 * M
    84  // TB = T = TiB = 1024 * G
    85  // PB = P = PiB = 1024 * T
    86  // EB = E = EiB = 1024 * P
    87  func ToBytes(s string) (uint64, error) {
    88  	s = strings.TrimSpace(s)
    89  	s = strings.ToUpper(s)
    90  
    91  	i := strings.IndexFunc(s, unicode.IsLetter)
    92  
    93  	if i == -1 {
    94  		return 0, invalidByteQuantityError
    95  	}
    96  
    97  	bytesString, multiple := s[:i], s[i:]
    98  	bytes, err := strconv.ParseFloat(bytesString, 64)
    99  	if err != nil || bytes <= 0 {
   100  		return 0, invalidByteQuantityError
   101  	}
   102  
   103  	switch multiple {
   104  	case "E", "EB", "EIB":
   105  		return uint64(bytes * EXABYTE), nil
   106  	case "P", "PB", "PIB":
   107  		return uint64(bytes * PETABYTE), nil
   108  	case "T", "TB", "TIB":
   109  		return uint64(bytes * TERABYTE), nil
   110  	case "G", "GB", "GIB":
   111  		return uint64(bytes * GIGABYTE), nil
   112  	case "M", "MB", "MIB":
   113  		return uint64(bytes * MEGABYTE), nil
   114  	case "K", "KB", "KIB":
   115  		return uint64(bytes * KILOBYTE), nil
   116  	case "B":
   117  		return uint64(bytes), nil
   118  	default:
   119  		return 0, invalidByteQuantityError
   120  	}
   121  }