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  }