github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/commons/bytex/format.go (about) 1 /* 2 * Copyright 2023 Wang Min Xiang 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 package bytex 19 20 import ( 21 "errors" 22 "strconv" 23 "strings" 24 "unicode" 25 ) 26 27 const ( 28 BYTE = 1 << (10 * iota) 29 KILOBYTE 30 MEGABYTE 31 GIGABYTE 32 TERABYTE 33 PETABYTE 34 EXABYTE 35 ) 36 37 var invalidByteQuantityError = errors.New("fns : byte quantity must be a positive integer with a unit of measurement like M, MB, MiB, G, GiB, or GB") 38 39 // FormatBytes returns a human-readable byte string of the form 10M, 12.5K, and so forth. The following units are available: 40 // 41 // E: Exabyte 42 // P: Petabyte 43 // T: Terabyte 44 // G: Gigabyte 45 // M: Megabyte 46 // K: Kilobyte 47 // B: Byte 48 // 49 // The unit that results in the smallest number greater than or equal to 1 is always chosen. 50 func FormatBytes(bytes uint64) string { 51 unit := "" 52 value := float64(bytes) 53 54 switch { 55 case bytes >= EXABYTE: 56 unit = "E" 57 value = value / EXABYTE 58 case bytes >= PETABYTE: 59 unit = "P" 60 value = value / PETABYTE 61 case bytes >= TERABYTE: 62 unit = "T" 63 value = value / TERABYTE 64 case bytes >= GIGABYTE: 65 unit = "G" 66 value = value / GIGABYTE 67 case bytes >= MEGABYTE: 68 unit = "M" 69 value = value / MEGABYTE 70 case bytes >= KILOBYTE: 71 unit = "K" 72 value = value / KILOBYTE 73 case bytes >= BYTE: 74 unit = "B" 75 case bytes == 0: 76 return "0B" 77 } 78 79 result := strconv.FormatFloat(value, 'f', 1, 64) 80 result = strings.TrimSuffix(result, ".0") 81 return result + unit 82 } 83 84 // ParseBytes parses a string formatted by FormatBytes as bytes. Note binary-prefixed and SI prefixed units both mean a base-2 units 85 // KB = K = KiB = 1024 86 // MB = M = MiB = 1024 * K 87 // GB = G = GiB = 1024 * M 88 // TB = T = TiB = 1024 * G 89 // PB = P = PiB = 1024 * T 90 // EB = E = EiB = 1024 * P 91 func ParseBytes(s string) (uint64, error) { 92 s = strings.TrimSpace(s) 93 s = strings.ToUpper(s) 94 95 i := strings.IndexFunc(s, unicode.IsLetter) 96 97 if i == -1 { 98 return 0, invalidByteQuantityError 99 } 100 101 bytesString, multiple := s[:i], s[i:] 102 bytes, err := strconv.ParseFloat(bytesString, 64) 103 if err != nil || bytes < 0 { 104 return 0, invalidByteQuantityError 105 } 106 107 switch multiple { 108 case "E", "EB", "EIB": 109 return uint64(bytes * EXABYTE), nil 110 case "P", "PB", "PIB": 111 return uint64(bytes * PETABYTE), nil 112 case "T", "TB", "TIB": 113 return uint64(bytes * TERABYTE), nil 114 case "G", "GB", "GIB": 115 return uint64(bytes * GIGABYTE), nil 116 case "M", "MB", "MIB": 117 return uint64(bytes * MEGABYTE), nil 118 case "K", "KB", "KIB": 119 return uint64(bytes * KILOBYTE), nil 120 case "B": 121 return uint64(bytes), nil 122 default: 123 return 0, invalidByteQuantityError 124 } 125 }